Compare commits
660 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9121c15d8 | |||
| 43bd00da86 | |||
| d124c89ced | |||
| ff5d64fcbf | |||
| ec01aadbe4 | |||
| f0a9de72b1 | |||
| 145c191a65 | |||
| 5cb5ef249b | |||
| ea38cef48c | |||
| 4808185b5c | |||
| b3d65b5703 | |||
| 0f38714e21 | |||
| 7a099bc268 | |||
| 6f1f6c75e6 | |||
| 40d5c37aea | |||
| 58499c2322 | |||
| 6428dc5cd2 | |||
| 5f5ff04636 | |||
| f21824a8e2 | |||
| 0ccd7e09de | |||
| 27039325f3 | |||
| 58c54cc3dc | |||
| 48349071ed | |||
| bb5ac900ec | |||
| 5efe45226d | |||
| a0183ff56f | |||
| bb091760af | |||
| 78d13871eb | |||
| fc5cf3e291 | |||
| 3182f251e1 | |||
| d6ba8655bb | |||
| 8114d01799 | |||
| 75844c5942 | |||
| 78d5c37267 | |||
| 397e89cbed | |||
| 2518e2f0ee | |||
| e833052e8e | |||
| 43e370f35a | |||
| 8d3c9e67a0 | |||
| 3988c0e3f0 | |||
| 723454b04d | |||
| 30c03435e4 | |||
| 5043533fde | |||
| d458973649 | |||
| 9c86b4bf88 | |||
| 3a6c6d8466 | |||
| d62167e364 | |||
| 9297d8af1d | |||
| bae9792f01 | |||
| b98af0f50f | |||
| 75e5cde39b | |||
| f853188bc7 | |||
| 61813a6f2c | |||
| 7a0c9776b4 | |||
| ee4f355e49 | |||
| bfc8c18675 | |||
| f1488767f8 | |||
| 2d5755c1dd | |||
| acc2e12f12 | |||
| eb2793bfa7 | |||
| 1a05843183 | |||
| ef17fd41f7 | |||
| 7bdbbbee50 | |||
| 2e800e6a0d | |||
| dae53a1128 | |||
| 2781bd02b5 | |||
| 7772ef22db | |||
| 2137c4e897 | |||
| 4a0e51bf34 | |||
| 9f581a7677 | |||
| be8869978d | |||
| 1ae044b91e | |||
| e550fb1a52 | |||
| fc65bb020f | |||
| a4dfdcd90d | |||
| 16d2e34148 | |||
| 567eefab1a | |||
| 1ef20ec622 | |||
| afab167e8c | |||
| af14ee0d47 | |||
| 0a5ca6eb25 | |||
| 6e9f24c08f | |||
| 07ac4087a3 | |||
| 1650c9f878 | |||
| 123963c14c | |||
| 1b45170ca3 | |||
| 9a0b677dac | |||
| b44f27dafa | |||
| 92d46edca3 | |||
| 471cf117ab | |||
| bf78bd4b8b | |||
| a0a0d7e344 | |||
| a9361571d6 | |||
| 1a13be9b5d | |||
| 0ed84c83c8 | |||
| 9670ca3b8a | |||
| d4476cb10b | |||
| 45c616639c | |||
| eedd646c28 | |||
| acbd4deb1b | |||
| 4e547a3639 | |||
| b910db0617 | |||
| bb382f3d2a | |||
| 25cb32ca6a | |||
| 6a13a7e096 | |||
| e366caf3d1 | |||
| cfa301f5ae | |||
| f72aa2415f | |||
| 7969a66552 | |||
| 4edba064d5 | |||
| f3a3c59b7b | |||
| aa54c23f98 | |||
| df1e2687d6 | |||
| 4f07e77bf9 | |||
| a10f570350 | |||
| ac94aa8e46 | |||
| 7ebf125dae | |||
| 9a361d573f | |||
| 1a423a252b | |||
| 7591f3f092 | |||
| 2cace3c73a | |||
| 97afafdd48 | |||
| 656efc5f92 | |||
| 46d055cf74 | |||
| 423e7439ee | |||
| 2262ef818e | |||
| 02459aad26 | |||
| 2451bb9a2b | |||
| cd9d2d0cec | |||
| fc636ea888 | |||
| e471aa8639 | |||
| 180f36d145 | |||
| f8fd87b896 | |||
| 130c8ea1b0 | |||
| 5af6330398 | |||
| daaf8713d8 | |||
| 5b02d9ed06 | |||
| b04cf20735 | |||
| 6531657ee0 | |||
| e28e7e37b8 | |||
| 467f59e193 | |||
| be9e6fe847 | |||
| b0e13611f7 | |||
| f3887aef33 | |||
| 7b3f891edd | |||
| b590f29f33 | |||
| 1debdc47cf | |||
| bb7662a214 | |||
| 53bc15900b | |||
| 90fe7af863 | |||
| 67ad24af08 | |||
| 67e9b7795a | |||
| 52332bc9ed | |||
| dc27d3bec9 | |||
| a711e608c9 | |||
| 2f7c04362e | |||
| 9b6fd7e19a | |||
| 9680b02bce | |||
| e7de7d1716 | |||
| 112f147596 | |||
| 413487de80 | |||
| 1158fa9ea8 | |||
| a8e8112b34 | |||
| 3df9260ca8 | |||
| 14ba3af086 | |||
| 71c8050883 | |||
| df5b01492c | |||
| 9dbb355e8d | |||
| 0f3778f07b | |||
| f515bd2dc8 | |||
| f3075facb4 | |||
| ed95adb45c | |||
| 95d4f7c62e | |||
| c90ed9f25f | |||
| 7f664a7971 | |||
| 14c6879f06 | |||
| d8d12d4590 | |||
| be3388d647 | |||
| 242836719d | |||
| 393c32558b | |||
| 94e723a88f | |||
| 14d8fb66aa | |||
| ae73d4cc7c | |||
| bf08e73f8f | |||
| 4a3f56acf2 | |||
| e33a4c2ef2 | |||
| 52bd7d0d68 | |||
| baad3b9d58 | |||
| 131edb611e | |||
| 518395bbc7 | |||
| 34b4499178 | |||
| 8f900fb4e1 | |||
| 9355689dd4 | |||
| 0909feaa6b | |||
| 7f18180105 | |||
| bee694e605 | |||
| 08525a3c20 | |||
| d70b36750c | |||
| 8c85d7bc97 | |||
| cb225cb1ce | |||
| 7e7ae3bb95 | |||
| 838579e9a8 | |||
| a99896618d | |||
| 24cb13d52b | |||
| cc7513e202 | |||
| c0b6d5aa2c | |||
| 5788038b49 | |||
| fbf0815b16 | |||
| e2c227f02b | |||
| be0f0fc421 | |||
| a03075b6ea | |||
| 3b3f1a817e | |||
| 601f7a6994 | |||
| 75d19d815d | |||
| d167d2a10f | |||
| fce4f0dc0e | |||
| 657039882c | |||
| cf99d42413 | |||
| f483eafae9 | |||
| 77bf28bcb6 | |||
| 6c2d06efb9 | |||
| d0081188c7 | |||
| ce2362459c | |||
| 4e568bec8a | |||
| 18c37c97b8 | |||
| 82e5faa869 | |||
| dec7122ac7 | |||
| a75fc8af7e | |||
| 86d2c2b153 | |||
| 9fc4565bc1 | |||
| f0cc418965 | |||
| 0bc3ca5c42 | |||
| 62ab867051 | |||
| 9fd3541520 | |||
| 3e559044b2 | |||
| 75a631b91f | |||
| 3a8786fdb7 | |||
| f2a89161b3 | |||
| 1c25057e42 | |||
| 590630e4e0 | |||
| 487dedba25 | |||
| f4c346a57c | |||
| 35365882ac | |||
| ea254ccc04 | |||
| 06d5b5f4b1 | |||
| 2536b02ace | |||
| 6b8abb1511 | |||
| 9c9f5be6fe | |||
| d8daec2e0a | |||
| c9b81d65f1 | |||
| 7f05029089 | |||
| 23c50ea9a5 | |||
| 2e5e8f363b | |||
| e63183649a | |||
| ef86c0273a | |||
| dd8d90aa39 | |||
| 670a46e85c | |||
| daf6c72005 | |||
| 1a4579b770 | |||
| 398c77bfdc | |||
| d45d322b54 | |||
| b0897a1fc9 | |||
| d00b469001 | |||
| c5a6cec194 | |||
| e2b1494511 | |||
| df76e6eacf | |||
| 541ae919d9 | |||
| 7976401aa2 | |||
| 7e10abe605 | |||
| afdf93ca63 | |||
| 321367b974 | |||
| 366f3aacef | |||
| 4b9ec9218d | |||
| cae66753fb | |||
| 5ac9efa9a3 | |||
| ded635207f | |||
| f0f37df76e | |||
| f5702532f0 | |||
| 2f02eee69b | |||
| 89c234b1c2 | |||
| c24052cb2d | |||
| a7a61a3620 | |||
| 135fdae209 | |||
| 5c30de517d | |||
| a7dc6162fa | |||
| 18778d3723 | |||
| 5ff1b5fd50 | |||
| 1c1f3dc42c | |||
| d67afc3bd0 | |||
| a5b857c753 | |||
| b00db3cc56 | |||
| 57720cb978 | |||
| 172e8d463f | |||
| 284dbb7553 | |||
| 1156eea8af | |||
| 17ee332715 | |||
| 2f258a3e3d | |||
| a31bca1798 | |||
| 791f77f641 | |||
| 1b6df232aa | |||
| 386272a618 | |||
| 7f8fc7add9 | |||
| 6bc525bc25 | |||
| de048e1009 | |||
| 68150d11b7 | |||
| f4f400ed87 | |||
| a49ccf0863 | |||
| 300879847f | |||
| d4c53945d9 | |||
| 21875100b6 | |||
| 87980643ea | |||
| 675f42401c | |||
| 3a5c09c424 | |||
| 3b462ffadc | |||
| d60af478ad | |||
| cabef8ff12 | |||
| 8a27ef30d5 | |||
| a111482217 | |||
| a758e825ed | |||
| af66f83a3d | |||
| b3605fa141 | |||
| 6f713985fb | |||
| 677e5a8cf1 | |||
| 872600a7a7 | |||
| 3a879bda4a | |||
| a6852cf4d2 | |||
| 61c601dbdf | |||
| 74bc06cc49 | |||
| 5fe1078013 | |||
| a011b07d99 | |||
| b392ed269b | |||
| 6059e9e119 | |||
| e6d792bdf7 | |||
| f16a4b6aef | |||
| d74b4f55fb | |||
| 693043e645 | |||
| e935a34946 | |||
| 4052e360c1 | |||
| cc6a2f2d49 | |||
| 07bc2fd742 | |||
| a57a6486e7 | |||
| a33276cb3d | |||
| bfec0059c5 | |||
| aea9dd1de5 | |||
| 954b54f914 | |||
| 56a15731ef | |||
| 766e59acde | |||
| f1a63f25e7 | |||
| 88dfdb7538 | |||
| 9072f7c6c9 | |||
| bff34063cd | |||
| 1e685ca835 | |||
| b55630aafa | |||
| c3b644797e | |||
| 1806dacb9d | |||
| abb7f23ca5 | |||
| b448c89655 | |||
| 8857391da7 | |||
| 50c008ead5 | |||
| 3e8837dd6e | |||
| ea1ff1e8bb | |||
| a7b155108d | |||
| 44c0c1bf0e | |||
| 7cd35a80b6 | |||
| e8973f08b5 | |||
| dd9c9520fb | |||
| aec033d8d2 | |||
| 5496b62b33 | |||
| e393e2eb4b | |||
| 10781a6e4b | |||
| 5a86004081 | |||
| 91ade1f33e | |||
| eaecf8137a | |||
| 92bb8fac32 | |||
| d4a7811078 | |||
| cb8dbcc172 | |||
| 495e68d23c | |||
| 20a0c4e3b5 | |||
| 4d773829f8 | |||
| bcb9804be8 | |||
| 5e59fa2598 | |||
| 6ea722d41e | |||
| 66346684a9 | |||
| 9731a31cb6 | |||
| ef3e016667 | |||
| 93e4d23143 | |||
| 0153a37cd7 | |||
| cce5846018 | |||
| a070f7cd5e | |||
| 4c11041477 | |||
| 166f526302 | |||
| f8718ffc1e | |||
| 31e4d3b725 | |||
| a766572a2f | |||
| 6a8824a467 | |||
| 0c3972d7b7 | |||
| 4a0eb2b3f1 | |||
| b3559ac74e | |||
| 4252bd2348 | |||
| 728338bfa8 | |||
| df8834fd88 | |||
| c8bc0eff11 | |||
| 8b6e869215 | |||
| 063893c109 | |||
| 44f4f20187 | |||
| 792b18f845 | |||
| 0671e478cd | |||
| d2fc27e21d | |||
| 740f27198f | |||
| 064f4b3fc6 | |||
| 5458676ead | |||
| 8337628323 | |||
| 7faaa4ce24 | |||
| 9583a72016 | |||
| e0102ddbf0 | |||
| 1030ad9a27 | |||
| ab8dcdcc40 | |||
| 773997a492 | |||
| 8333c80b7a | |||
| 96644ab6b9 | |||
| f977c53ecb | |||
| 8c1843b351 | |||
| c9e86ac194 | |||
| f7449921e9 | |||
| 5f79534f4a | |||
| 3bcd5d94d6 | |||
| 01348187c8 | |||
| b26a4ad333 | |||
| 89f45d3d05 | |||
| e83a062eda | |||
| 1ea667e709 | |||
| 5326ebd136 | |||
| 4db9892f8c | |||
| 880828379e | |||
| 9b54077409 | |||
| 9f478b51e2 | |||
| 7c77e03c5a | |||
| 9d3aed42b7 | |||
| 3dedd51b84 | |||
| 711c713ab8 | |||
| 5bc5e9f108 | |||
| 9770692d07 | |||
| 133da6569b | |||
| 985e683896 | |||
| c3698053ea | |||
| dba06a3a9e | |||
| 07b1062fb2 | |||
| be0933a708 | |||
| d31f185cce | |||
| 5901182885 | |||
| f033aeda83 | |||
| 53f9e2bc7a | |||
| 514db05770 | |||
| 7ca617f077 | |||
| 8f5ac5fb55 | |||
| 54f828743e | |||
| f519fb747f | |||
| 36f714e414 | |||
| 773c773773 | |||
| 3071a83ae0 | |||
| 1c4864a3cc | |||
| 50c92d4730 | |||
| f8a0bf6a4b | |||
| 910fc08406 | |||
| eebc56d54b | |||
| b5ddc2c85b | |||
| 4e03ebe284 | |||
| 7577fc61e4 | |||
| d302675056 | |||
| 5316f41eba | |||
| fa6c463d46 | |||
| 23a441e7c8 | |||
| ac993184ee | |||
| 1dbc1f4aa2 | |||
| fe65de1207 | |||
| 089704c4f9 | |||
| bb933e5214 | |||
| eb34cf7917 | |||
| 4909cf2a9e | |||
| 37f9cca5ec | |||
| 72192257f2 | |||
| e0050bc844 | |||
| d2d0842737 | |||
| fe3b9f9e86 | |||
| 0ea6671bfa | |||
| 9209675d45 | |||
| 3e44f39f4d | |||
| 1f6ab340a6 | |||
| f208869aff | |||
| c031686825 | |||
| 791c39d977 | |||
| aac432b00c | |||
| 2b5b3273e2 | |||
| 4f57eebf24 | |||
| 0c9a1a8922 | |||
| fa2a3e4b03 | |||
| 94a337fc9e | |||
| 8d9cdf9c15 | |||
| fb8d52d599 | |||
| 070c36ffe6 | |||
| 5db1c50816 | |||
| 43e97ea6ea | |||
| 8fdedf9441 | |||
| b67ed3eac2 | |||
| 116ce931ce | |||
| 15d0fb4feb | |||
| 132b164a74 | |||
| bdbe2c3ac6 | |||
| 2db6cf85a7 | |||
| 5be7dee3d3 | |||
| 72799973e7 | |||
| d8a8e03bf6 | |||
| a243823e5e | |||
| a4cf601c98 | |||
| 1e3c0d597e | |||
| 91822d2e45 | |||
| 43c5b412ca | |||
| 08ff71aae3 | |||
| 5d83516659 | |||
| f39005d295 | |||
| 0e6c82776a | |||
| 67616dbcf4 | |||
| 5881eef2c6 | |||
| 4839985f38 | |||
| aa841a4674 | |||
| 6d1de73cad | |||
| e0b64a4879 | |||
| 0a6626891e | |||
| 2ec7644a33 | |||
| 810578ff5d | |||
| 64eafb062e | |||
| ad56928d04 | |||
| 30583f920d | |||
| 5130a86854 | |||
| e4e32307de | |||
| e34ea32a5e | |||
| b8e6df545a | |||
| 90a4ce5723 | |||
| 8333089278 | |||
| 70344cc02e | |||
| 4adb990a5d | |||
| 160a147a58 | |||
| bd384d3f10 | |||
| ad8143b0bd | |||
| f439970e7a | |||
| 625f120813 | |||
| a37a576ee5 | |||
| 2bd0679a81 | |||
| b7eb72fe49 | |||
| afb3843fad | |||
| 8e85d316c9 | |||
| ebd3c11129 | |||
| 75acb0f28a | |||
| eb5f33e815 | |||
| 8c64e7359a | |||
| 14495cd1da | |||
| 93eba43b76 | |||
| adbac82c30 | |||
| e467ce912b | |||
| 4eab5fd075 | |||
| d0e8a4ca09 | |||
| bcd0671213 | |||
| 266a9e5328 | |||
| a37fbe6abf | |||
| 52901f50eb | |||
| 340c59969c | |||
| 8706b6d8a9 | |||
| 5d29f77d60 | |||
| 61a6c83418 | |||
| deda1c2fd6 | |||
| 4669bb54fe | |||
| 319eae7810 | |||
| 8449b5ca1e | |||
| e4b24e17f3 | |||
| 981741062b | |||
| a55adfc0a1 | |||
| f609146c29 | |||
| 891009dc67 | |||
| ab23e04c65 | |||
| 877b1bd0a3 | |||
| c0d352dd7d | |||
| bef895eaf4 | |||
| 014a32b050 | |||
| 937472feb0 | |||
| f14a4d3bc7 | |||
| 9e9d371e1c | |||
| 9e2bcfe168 | |||
| eaeb74c576 | |||
| 23891054dc | |||
| cfc4c58da3 | |||
| 5f187f71c8 | |||
| b2250ecb7a | |||
| 1453b36484 | |||
| 4b21d9e7f4 | |||
| 4644f1479b | |||
| 3bf2328db2 | |||
| 7d637eaa5a | |||
| 32111a863b | |||
| 0ed59753da | |||
| 75f5f3a0a8 | |||
| 07679aa376 | |||
| b7b21689f2 | |||
| b426fa352e | |||
| a771984619 | |||
| 71828d5461 | |||
| d9817ec696 | |||
| 33ded3f18a | |||
| 004d567253 | |||
| e2fd5199c3 | |||
| b7b3b1a776 | |||
| 4078e4e323 | |||
| 64d457425e | |||
| 524ef8261b | |||
| 344dcc10c1 | |||
| 2ad97ca040 | |||
| 7880e15672 | |||
| ceffbb950f | |||
| b941ea6950 | |||
| 54c1659210 | |||
| b4a0d33ba8 | |||
| 4e65a8d755 | |||
| bf028adcc3 | |||
| 137b558bef | |||
| be5be7a8b9 | |||
| 2b3a1ee120 | |||
| d316a3f044 | |||
| 105750bfde | |||
| 3e34027ae0 | |||
| 0f9559c1ff | |||
| 11db243514 | |||
| d391980b06 | |||
| a8eb138ae0 | |||
| 72493d54aa | |||
| 91c7a89f93 | |||
| 11f540daaf | |||
| 700b4ef058 | |||
| 1fc0adf7b7 | |||
| 58875d5606 | |||
| 0dfc98a493 | |||
| 15a1db480a | |||
| 3dc4f56fb4 | |||
| 7da8ec8448 | |||
| a973c0626e | |||
| 213d990e47 | |||
| a5fbfdbab4 | |||
| b705878318 | |||
| 925529923a | |||
| 13ce7513f0 | |||
| 7a1b17ff6a | |||
| 8ebe64e630 | |||
| c07a244bab | |||
| 8a032ee040 | |||
| a835401cb2 | |||
| 2cd7c7a357 | |||
| dafe353050 | |||
| b5378eff64 | |||
| 570dd09dcd | |||
| 0df9dd8320 | |||
| 0d49fc3a2e | |||
| 43d92bec5b |
@@ -2621,6 +2621,51 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "denzfarid",
|
||||
"name": "denzfarid",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1294403?v=4",
|
||||
"profile": "https://github.com/denzfarid",
|
||||
"contributions": []
|
||||
},
|
||||
{
|
||||
"login": "ntbutler-nbcs",
|
||||
"name": "ntbutler-nbcs",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/94018771?v=4",
|
||||
"profile": "https://github.com/ntbutler-nbcs",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "naveensrinivasan",
|
||||
"name": "Naveen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/172697?v=4",
|
||||
"profile": "https://naveensrinivasan.dev",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mikeroq",
|
||||
"name": "Mike Roquemore",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/55674383?v=4",
|
||||
"profile": "https://github.com/mikeroq",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "reederda",
|
||||
"name": "Daniel Reeder",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7991086?v=4",
|
||||
"profile": "https://github.com/reederda",
|
||||
"contributions": [
|
||||
"translations",
|
||||
"translation",
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+10
-3
@@ -70,11 +70,13 @@ IMAGE_LIB=gd
|
||||
MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
||||
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||
BACKUP_ENV=true
|
||||
|
||||
ALLOW_BACKUP_DELETE=false
|
||||
ALLOW_DATA_PURGE=false
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SESSION SETTINGS
|
||||
# --------------------------------------------
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=12000
|
||||
EXPIRE_ON_CLOSE=false
|
||||
ENCRYPT=false
|
||||
@@ -97,7 +99,6 @@ ENABLE_HSTS=false
|
||||
# OPTIONAL: CACHE SETTINGS
|
||||
# --------------------------------------------
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
QUEUE_DRIVER=sync
|
||||
CACHE_PREFIX=snipeit
|
||||
|
||||
@@ -146,7 +147,13 @@ AWS_DEFAULT_REGION=null
|
||||
# --------------------------------------------
|
||||
LOGIN_MAX_ATTEMPTS=5
|
||||
LOGIN_LOCKOUT_DURATION=60
|
||||
RESET_PASSWORD_LINK_EXPIRES=900
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: FORGOTTEN PASSWORD SETTINGS
|
||||
# --------------------------------------------
|
||||
RESET_PASSWORD_LINK_EXPIRES=15
|
||||
PASSWORD_CONFIRM_TIMEOUT=10800
|
||||
PASSWORD_RESET_MAX_ATTEMPTS_PER_MIN=50
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: MISC
|
||||
|
||||
+1
-1
@@ -15,8 +15,8 @@
|
||||
# *.js @octocat @github/js
|
||||
|
||||
|
||||
app/Importer/* @dmeltzer
|
||||
app/Http/Controllers/CustomFields* @uberbrady
|
||||
app/Http/Controllers/Api/CustomFields* @uberbrady
|
||||
resources/views/custom_fields/* @uberbrady
|
||||
docker/* @uberbrady
|
||||
app/Providers/SamlServiceProvider.php @uberbrady
|
||||
|
||||
+17
-3
@@ -1,4 +1,18 @@
|
||||
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*"]
|
||||
backend: ["/app", "*.php"]
|
||||
legal: ["LICENSE*", "NOTICES*"]
|
||||
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*", "*livewire*"]
|
||||
skins: ["*.js", "*.css", "*.scss", "*.less"]
|
||||
css: ["*.css","*.scss", "*.less"]
|
||||
backend: ["/app/*", "*.php"]
|
||||
backups: ["*backup*"]
|
||||
restore: ["*restore*"]
|
||||
saml: ["*saml*"]
|
||||
scim: ["*scim*"]
|
||||
custom fields: ["*fields*", "*fieldsets*"]
|
||||
dependencies: ["composer.json"]
|
||||
consumables: ["*consumables*"]
|
||||
api: ["/app/Http/Controllers/api/*"]
|
||||
notifications: ["/app/Notifications/*"]
|
||||
importer: ["/app/Importer/*"]
|
||||
cli / artisan: ["/app/Console/*"]
|
||||
LDAP: ["*LDAP*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
|
||||
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
|
||||
config: .github
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -30,10 +30,10 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
@@ -17,8 +17,16 @@ on:
|
||||
schedule:
|
||||
- cron: '36 23 * * 3'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
# Ensure schedule job never runs on forked repos. It's only executed for 'snipe/snipe-it'
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||
if: (github.repository == 'snipe/snipe-it') || ((github.repository != 'snipe/snipe-it') && (github.event_name != 'schedule'))
|
||||
name: Codacy Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -28,7 +36,7 @@ jobs:
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@1.1.0
|
||||
uses: codacy/codacy-analysis-cli-action@v4.1.0
|
||||
with:
|
||||
# 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
|
||||
@@ -44,6 +52,6 @@ jobs:
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF results file
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -15,6 +15,9 @@ on:
|
||||
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
|
||||
@@ -42,13 +45,13 @@ jobs:
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
@@ -60,7 +63,7 @@ jobs:
|
||||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
@@ -69,7 +72,7 @@ jobs:
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push 'snipe-it' image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.alpine
|
||||
|
||||
@@ -15,6 +15,9 @@ on:
|
||||
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
|
||||
@@ -42,13 +45,13 @@ jobs:
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
@@ -60,7 +63,7 @@ jobs:
|
||||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
@@ -69,7 +72,7 @@ jobs:
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push 'snipe-it' image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
@@ -23,6 +23,7 @@ php7.4-xml \
|
||||
php7.4-mbstring \
|
||||
php7.4-zip \
|
||||
php7.4-bcmath \
|
||||
php7.4-redis \
|
||||
patch \
|
||||
curl \
|
||||
wget \
|
||||
|
||||
@@ -27,6 +27,7 @@ RUN apk add --no-cache \
|
||||
php7-xmlwriter \
|
||||
php7-xmlreader \
|
||||
php7-sodium \
|
||||
php7-redis \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
 [](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)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
||||
@@ -65,6 +65,7 @@ Since the release of the JSON REST API, several third-party developers have been
|
||||
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
|
||||
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
|
||||
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
|
||||
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@RodneyLeeBrands](https://github.com/RodneyLeeBrands) - Python script to synchronize information between Mosyle and 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. :)
|
||||
|
||||
@@ -131,7 +132,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use DB;
|
||||
|
||||
class GeneratePersonalAccessToken extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:make-api-key
|
||||
{--user_id= : The ID of the user to create the token for.}
|
||||
{--name= : The name of the new API token}
|
||||
{--key-only : Only return the value of the API key}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This console command allows you to generate Personal API tokens to be used with the Snipe-IT JSON REST API on behalf of a user.';
|
||||
|
||||
|
||||
/**
|
||||
* The token repository implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokenRepository;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
|
||||
{
|
||||
$this->validation = $validation;
|
||||
$this->tokenRepository = $tokenRepository;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$accessTokenName = $this->option('name');
|
||||
if ($accessTokenName=='') {
|
||||
$accessTokenName = 'CLI Auth Token';
|
||||
}
|
||||
|
||||
if ($this->option('user_id')=='') {
|
||||
return $this->error('ERROR: user_id cannot be blank.');
|
||||
}
|
||||
|
||||
if ($user = User::find($this->option('user_id'))) {
|
||||
|
||||
$createAccessToken = $user->createToken($accessTokenName)->accessToken;
|
||||
|
||||
if ($this->option('key-only')) {
|
||||
$this->info($createAccessToken);
|
||||
|
||||
} else {
|
||||
|
||||
$this->warn('Your API Token has been created. Be sure to copy this token now, as it will not be accessible again.');
|
||||
|
||||
if ($token = DB::table('oauth_access_tokens')->where('user_id', '=', $user->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first()) {
|
||||
$this->info('API Token ID: '.$token->id);
|
||||
}
|
||||
|
||||
$this->info('API Token User: '.$user->present()->fullName.' ('.$user->username.')');
|
||||
$this->info('API Token Name: '.$accessTokenName);
|
||||
$this->info('API Token: '.$createAccessToken);
|
||||
}
|
||||
} else {
|
||||
return $this->error('ERROR: Invalid user. API key was not created.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class LdapSync extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--summary} {--json_summary}';
|
||||
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--filter=} {--summary} {--json_summary}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -80,7 +80,11 @@ class LdapSync extends Command
|
||||
} else {
|
||||
$search_base = null;
|
||||
}
|
||||
$results = Ldap::findLdapUsers($search_base);
|
||||
if ($this->option('filter') != '') {
|
||||
$results = Ldap::findLdapUsers($search_base, -1, $this->option('filter'));
|
||||
} else {
|
||||
$results = Ldap::findLdapUsers($search_base);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if ($this->option('json_summary')) {
|
||||
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
|
||||
@@ -109,7 +113,7 @@ class LdapSync extends Command
|
||||
}
|
||||
|
||||
/* Process locations with explicitly defined OUs, if doing a full import. */
|
||||
if ($this->option('base_dn') == '') {
|
||||
if ($this->option('base_dn') == '' && $this->option('filter') == '') {
|
||||
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
|
||||
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
|
||||
$ldap_ou_lengths = [];
|
||||
|
||||
@@ -27,6 +27,19 @@ function ip_in_range( $ip, $range ) {
|
||||
}
|
||||
// NOTE - this function was shamelessly stolen from this gist: https://gist.github.com/tott/7684443
|
||||
|
||||
/**
|
||||
* Ensure LDAP filters are parentheses-wrapped
|
||||
*/
|
||||
function parenthesized_filter($filter)
|
||||
{
|
||||
if(substr($filter,0,1) == "(" ) {
|
||||
return $filter;
|
||||
} else {
|
||||
return "(".$filter.")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LdapTroubleshooter extends Command
|
||||
{
|
||||
/**
|
||||
@@ -70,6 +83,47 @@ class LdapTroubleshooter extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the results from ldap_get_entries into something useful
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
public function ldap_results_cleaner ($array) {
|
||||
$cleaned = [];
|
||||
for($i = 0; $i < $array['count']; $i++) {
|
||||
$row = $array[$i];
|
||||
$clean_row = [];
|
||||
foreach($row AS $key => $val ) {
|
||||
$this->debugout("Key is: ".$key);
|
||||
if($key == "count" || is_int($key) || $key == "dn") {
|
||||
$this->debugout(" and we're gonna skip it\n");
|
||||
continue;
|
||||
}
|
||||
$this->debugout(" And that seems fine.\n");
|
||||
if(array_key_exists('count',$val)) {
|
||||
if($val['count'] == 1) {
|
||||
$clean_row[$key] = $val[0];
|
||||
} else {
|
||||
unset($val['count']); //these counts are annoying
|
||||
$elements = [];
|
||||
foreach($val as $entry) {
|
||||
if(isset($ldap_constants[$entry])) {
|
||||
$elements[] = $ldap_constants[$entry];
|
||||
} else {
|
||||
$elements[] = $entry;
|
||||
}
|
||||
}
|
||||
$clean_row[$key] = $elements;
|
||||
}
|
||||
} else {
|
||||
$clean_row[$key] = $val;
|
||||
}
|
||||
}
|
||||
$cleaned[$i] = $clean_row;
|
||||
}
|
||||
return $cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
@@ -102,16 +156,12 @@ class LdapTroubleshooter extends Command
|
||||
$output[] = "LDAPTLS_KEY=storage/ldap_client_tls.key";
|
||||
}
|
||||
$output[] = "ldapsearch";
|
||||
$output[] = $settings->ldap_server;
|
||||
$output[] = "-H ".$settings->ldap_server;
|
||||
$output[] = "-x";
|
||||
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
||||
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
||||
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
|
||||
if(substr($settings->ldap_filter,0,1) == "(" ) {
|
||||
$output[] = escapeshellarg($settings->ldap_filter);
|
||||
} else {
|
||||
$output[] = escapeshellarg("(".$settings->ldap_filter.")");
|
||||
}
|
||||
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
|
||||
if($settings->ldap_tls) {
|
||||
$this->line("# adding STARTTLS option");
|
||||
$output[] = "-Z";
|
||||
@@ -290,45 +340,8 @@ class LdapTroubleshooter extends Command
|
||||
}
|
||||
$this->debugout("LDAP constants are: ".print_r($ldap_constants,true));
|
||||
|
||||
// recursive function that 'cleans' the returned array from ldap_get_entries which are formatted awfully
|
||||
$cleaner = function ($array) {
|
||||
$cleaned = [];
|
||||
for($i = 0; $i < $array['count']; $i++) {
|
||||
$row = $array[$i];
|
||||
$clean_row = [];
|
||||
foreach($row AS $key => $val ) {
|
||||
$this->debugout("Key is: ".$key);
|
||||
if($key == "count" || is_int($key) || $key == "dn") {
|
||||
$this->debugout(" and we're gonna skip it\n");
|
||||
continue;
|
||||
}
|
||||
$this->debugout(" And that seems fine.\n");
|
||||
if(array_key_exists('count',$val)) {
|
||||
if($val['count'] == 1) {
|
||||
$clean_row[$key] = $val[0];
|
||||
} else {
|
||||
unset($val['count']); //these counts are annoying
|
||||
$elements = [];
|
||||
foreach($val as $entry) {
|
||||
if(isset($ldap_constants[$entry])) {
|
||||
$elements[] = $ldap_constants[$entry];
|
||||
} else {
|
||||
$elements[] = $entry;
|
||||
}
|
||||
}
|
||||
$clean_row[$key] = $elements;
|
||||
}
|
||||
} else {
|
||||
$clean_row[$key] = $val;
|
||||
}
|
||||
}
|
||||
$cleaned[$i] = $clean_row;
|
||||
}
|
||||
return $cleaned;
|
||||
};
|
||||
|
||||
foreach($ldap_urls AS $ldap_url) {
|
||||
if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword))) {
|
||||
if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword),$settings)) {
|
||||
$this->info("Success getting informational bind!");
|
||||
} else {
|
||||
$this->error("Unable to get information from bind.");
|
||||
@@ -422,9 +435,9 @@ class LdapTroubleshooter extends Command
|
||||
});
|
||||
}
|
||||
|
||||
public function test_informational_bind($ldap_url, $check_cert, $start_tls, $username, $password)
|
||||
public function test_informational_bind($ldap_url, $check_cert, $start_tls, $username, $password,$settings)
|
||||
{
|
||||
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
|
||||
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password, $settings) {
|
||||
try { // TODO - copypasta'ed from test_authed_bind
|
||||
$conn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
|
||||
$bind_results = ldap_bind($conn, $username, $password);
|
||||
@@ -435,12 +448,13 @@ class LdapTroubleshooter extends Command
|
||||
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
|
||||
$result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/);
|
||||
$results = ldap_get_entries($conn, $result);
|
||||
$cleaned_results = $cleaner($results);
|
||||
$cleaned_results = $this->ldap_results_cleaner($results);
|
||||
$this->line(print_r($cleaned_results,true));
|
||||
//okay, great - now how do we display those results? I have no idea.
|
||||
// I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it?
|
||||
$this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?");
|
||||
$search_results = ldap_search($conn, $settings->base_dn, $settings->filter);
|
||||
$this->debugout("Base DN is: ".$settings->ldap_basedn." and filter is: ".parenthesized_filter($settings->ldap_filter));
|
||||
$search_results = ldap_search($conn, $settings->ldap_basedn, parenthesized_filter($settings->ldap_filter));
|
||||
$this->info("Printing first 10 results: ");
|
||||
for($i=0;$i<10;$i++) {
|
||||
$this->info($search_results[$i]);
|
||||
|
||||
@@ -41,10 +41,20 @@ class MergeUsersByUsername extends Command
|
||||
{
|
||||
// Get the list of users who have an email address as their username
|
||||
$users = User::where('username', 'LIKE', '%@%')->whereNull('deleted_at')->get();
|
||||
$this->info($users->count().' total non-deleted users whose usernames contain a @ symbol.');
|
||||
|
||||
|
||||
foreach ($users as $user) {
|
||||
$parts = explode('@', $user->username);
|
||||
$bad_users = User::where('username', '=', $parts[0])->whereNull('deleted_at')->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')->get();
|
||||
$parts = explode('@', trim($user->username));
|
||||
$this->info('Checking against username '.trim($parts[0]).'.');
|
||||
|
||||
|
||||
$bad_users = User::where('username', '=', trim($parts[0]))
|
||||
->whereNull('deleted_at')
|
||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
|
||||
->get();
|
||||
|
||||
|
||||
|
||||
foreach ($bad_users as $bad_user) {
|
||||
$this->info($bad_user->username.' ('.$bad_user->id.') will be merged into '.$user->username.' ('.$user->id.') ');
|
||||
|
||||
@@ -71,22 +71,31 @@ class ReEncodeCustomFieldNames extends Command
|
||||
*/
|
||||
$last_part = substr(strrchr($asset_column, '_snipeit_'), 1);
|
||||
$custom_field_columns[$last_part] = $asset_column;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$this->info($field->name.' ('.$field->id.') column should be '.$field->convertUnicodeDbSlug().'');
|
||||
$this->info($field->name.' ('.$field->id.') column should be '.$field->convertUnicodeDbSlug());
|
||||
|
||||
/** The assets table has the column it should have, all is well */
|
||||
if (\Schema::hasColumn('assets', $field->convertUnicodeDbSlug())) {
|
||||
$this->info('-- ✓ This field exists - all good');
|
||||
if ($field->db_column == $field->convertUnicodeDbSlug() && \Schema::hasColumn('assets', $field->convertUnicodeDbSlug())) {
|
||||
$this->info('-- ✓ This field exists on the assets table and the value for db_column matches in the custom_fields table.');
|
||||
|
||||
/**
|
||||
* There is a mismatch between the fieldname on the assets table and
|
||||
* what $field->convertUnicodeDbSlug() is *now* expecting.
|
||||
*/
|
||||
} else {
|
||||
$this->warn('-- X Field mismatch: updating... ');
|
||||
|
||||
if ($field->db_column != $field->convertUnicodeDbSlug()) {
|
||||
$this->error('-- ✘ Field mismatch: '.$field->name.' value should be '.$field->convertUnicodeDbSlug().' but is '.$field->db_column.' in the custom_fields table');
|
||||
|
||||
} else {
|
||||
$this->error('-- ✘ Field mismatch: '.$field->name.' column should be '.$field->convertUnicodeDbSlug().' but is '.$custom_field_columns[$field->id].' on the assets table.');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Make sure the custom_field_columns array has the ID */
|
||||
if (array_key_exists($field->id, $custom_field_columns)) {
|
||||
@@ -95,13 +104,19 @@ class ReEncodeCustomFieldNames extends Command
|
||||
* Update the asset schema to the corrected fieldname that will be recognized by the
|
||||
* system elsewhere that we use $field->convertUnicodeDbSlug()
|
||||
*/
|
||||
$this->info('-- ✓ Updating field from '.$field->db_column.' to '.$field->convertUnicodeDbSlug().' in the assets table');
|
||||
\Schema::table('assets', function ($table) use ($custom_field_columns, $field) {
|
||||
$table->renameColumn($custom_field_columns[$field->id], $field->convertUnicodeDbSlug());
|
||||
});
|
||||
|
||||
$this->warn('-- ✓ Field updated from '.$custom_field_columns[$field->id].' to '.$field->convertUnicodeDbSlug());
|
||||
$this->info('-- ✓ Updating field from '.$field->db_column.' to '.$field->convertUnicodeDbSlug().' in the custom fields table');
|
||||
|
||||
$field->db_column = $field->convertUnicodeDbSlug();
|
||||
$field->save();
|
||||
|
||||
|
||||
} else {
|
||||
$this->warn('-- X WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
|
||||
$this->warn('-- ✘ WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class RegenerateAssetTags extends Command
|
||||
}
|
||||
|
||||
foreach ($total_assets as $asset) {
|
||||
$start_tag++;
|
||||
|
||||
$output['info'][] = 'Asset tag:'.$asset->asset_tag;
|
||||
$asset->asset_tag = $settings->auto_increment_prefix.$settings->auto_increment_prefix.$start_tag;
|
||||
|
||||
@@ -72,8 +72,15 @@ class RegenerateAssetTags extends Command
|
||||
|
||||
// Use forceSave here to override model level validation
|
||||
$asset->forceSave();
|
||||
$start_tag++;
|
||||
if ($bar) {
|
||||
$bar->advance();
|
||||
}
|
||||
}
|
||||
|
||||
$settings->next_auto_tag_base = Asset::zerofill($start_tag, $settings->zerofill_count);
|
||||
$settings->save();
|
||||
|
||||
$bar->finish();
|
||||
$this->info("\n");
|
||||
|
||||
|
||||
@@ -227,6 +227,9 @@ class RestoreFromBackup extends Command
|
||||
return $this->error('Unable to invoke mysql via CLI');
|
||||
}
|
||||
|
||||
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
||||
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
||||
|
||||
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
|
||||
// $this->info("Stderr says? ".fgets($pipes[2])); //FIXME: ditto, same.
|
||||
// should we read stdout?
|
||||
@@ -247,18 +250,25 @@ class RestoreFromBackup extends Command
|
||||
}
|
||||
$bytes_read = 0;
|
||||
|
||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$bytes_written = fwrite($pipes[0], $buffer);
|
||||
try {
|
||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$bytes_written = fwrite($pipes[0], $buffer);
|
||||
|
||||
if ($bytes_written === false) {
|
||||
$stdout = fgets($pipes[1]);
|
||||
$this->info($stdout);
|
||||
$stderr = fgets($pipes[2]);
|
||||
$this->info($stderr);
|
||||
return false;
|
||||
if ($bytes_written === false) {
|
||||
throw new Exception("Unable to write to pipe");
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
||||
$err_out = fgets($pipes[1]);
|
||||
$err_err = fgets($pipes[2]);
|
||||
\Log::error("Error OUTPUT: ".$err_out);
|
||||
$this->info($err_out);
|
||||
\Log::error("Error ERROR : ".$err_err);
|
||||
$this->error($err_err);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!feof($sql_contents) || $bytes_read == 0) {
|
||||
|
||||
@@ -24,6 +24,7 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->command('snipeit:backup')->weekly();
|
||||
$schedule->command('backup:clean')->daily();
|
||||
$schedule->command('snipeit:upcoming-audits')->daily();
|
||||
$schedule->command('auth:clear-resets')->everyFifteenMinutes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ class Handler extends ExceptionHandler
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
if ($this->shouldReport($exception)) {
|
||||
Log::error($exception);
|
||||
\Log::error($exception);
|
||||
return parent::report($exception);
|
||||
}
|
||||
}
|
||||
|
||||
+49
-13
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
@@ -842,6 +841,16 @@ class Helper
|
||||
return preg_replace('/\s+/u', '_', trim($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array (or null) of the the raw and formatted date object for easy use in
|
||||
* the API and the bootstrap table listings.
|
||||
*
|
||||
* @param $date
|
||||
* @param $type
|
||||
* @param $array
|
||||
* @return array|string|null
|
||||
*/
|
||||
|
||||
public static function getFormattedDateObject($date, $type = 'datetime', $array = true)
|
||||
{
|
||||
if ($date == '') {
|
||||
@@ -849,21 +858,42 @@ class Helper
|
||||
}
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$tmp_date = new \Carbon($date);
|
||||
|
||||
if ($type == 'datetime') {
|
||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
|
||||
} else {
|
||||
$dt['date'] = $tmp_date->format('Y-m-d');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
|
||||
/**
|
||||
* Wrap this in a try/catch so that if Carbon crashes, for example if the $date value
|
||||
* isn't actually valid, we don't crash out completely.
|
||||
*
|
||||
* While this *shouldn't* typically happen since we validate dates before entering them
|
||||
* into the database (and we use date/datetime fields for native fields in the system),
|
||||
* it is a possible scenario that a custom field could be created as an "ANY" field, data gets
|
||||
* added, and then the custom field format gets edited later. If someone put bad data in the
|
||||
* database before then - or if they manually edited the field's value - it will crash.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
$tmp_date = new \Carbon($date);
|
||||
|
||||
if ($type == 'datetime') {
|
||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
|
||||
} else {
|
||||
$dt['date'] = $tmp_date->format('Y-m-d');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
|
||||
}
|
||||
|
||||
if ($array == 'true') {
|
||||
return $dt;
|
||||
}
|
||||
|
||||
return $dt['formatted'];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::warning($e);
|
||||
return $date.' (Invalid '.$type.' value.)';
|
||||
}
|
||||
|
||||
if ($array == 'true') {
|
||||
return $dt;
|
||||
}
|
||||
|
||||
return $dt['formatted'];
|
||||
}
|
||||
|
||||
// Nicked from Drupal :)
|
||||
@@ -1089,4 +1119,10 @@ class Helper
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
public static function SettingUrls(){
|
||||
$settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index'];
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\Accessory;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Redirect;
|
||||
|
||||
/** This controller handles all actions related to Accessories for
|
||||
@@ -130,6 +131,17 @@ class AccessoriesController extends Controller
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$min = $accessory->numCheckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
"qty" => "required|numeric|min:$min"
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$this->authorize($accessory);
|
||||
|
||||
// Update the accessory data
|
||||
|
||||
@@ -12,9 +12,13 @@ use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\License;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -23,6 +27,7 @@ use Illuminate\Support\Str;
|
||||
use App\Http\Controllers\SettingsController;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Carbon\Carbon;
|
||||
use phpDocumentor\Reflection\Types\Compound;
|
||||
|
||||
class AcceptanceController extends Controller
|
||||
{
|
||||
@@ -106,87 +111,143 @@ class AcceptanceController extends Controller
|
||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
||||
}
|
||||
|
||||
$sig_filename = '';
|
||||
if ($request->filled('signature_output')) {
|
||||
$sig_filename = 'siglog-'.Str::uuid().'-'.date('Y-m-d-his').'.png';
|
||||
$data_uri = e($request->input('signature_output'));
|
||||
$encoded_image = explode(',', $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
$acceptance->stored_eula_file = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
||||
$path = Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
|
||||
}
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
$acceptance->accept($sig_filename);
|
||||
|
||||
event(new CheckoutAccepted($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
|
||||
|
||||
} else {
|
||||
$acceptance->decline($sig_filename);
|
||||
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
|
||||
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
|
||||
$display_model = '';
|
||||
$pdf_view_route = '';
|
||||
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
||||
$sig_filename='';
|
||||
|
||||
if ($acceptance->checkoutable_type== 'App\Models\Asset') {
|
||||
$assigned_to = User::find($item->assigned_to);
|
||||
$asset_model = AssetModel::find($item->model_id);
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
|
||||
/**
|
||||
* Check for the eula-pdfs directory
|
||||
*/
|
||||
if (! Storage::exists('private_uploads/eula-pdfs')) {
|
||||
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->require_accept_signature == '1') {
|
||||
|
||||
// Check if the signature directory exists, if not create it
|
||||
if (!Storage::exists('private_uploads/signatures')) {
|
||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
||||
}
|
||||
|
||||
// The item was accepted, check for a signature
|
||||
if ($request->filled('signature_output')) {
|
||||
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
|
||||
$data_uri = $request->input('signature_output');
|
||||
$encoded_image = explode(',', $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
|
||||
|
||||
// No image data is present, kick them back.
|
||||
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
|
||||
} else {
|
||||
return redirect()->back()->with('error', trans('general.shitty_browser'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this is horrible
|
||||
switch($acceptance->checkoutable_type){
|
||||
case 'App\Models\Asset':
|
||||
$pdf_view_route ='account.accept.accept-asset-eula';
|
||||
$asset_model = AssetModel::find($item->model_id);
|
||||
$display_model = $asset_model->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\Accessory':
|
||||
$pdf_view_route ='account.accept.accept-accessory-eula';
|
||||
$accessory = Accessory::find($item->id);
|
||||
$display_model = $accessory->name;
|
||||
$assigned_to = User::find($item->assignedTo);
|
||||
break;
|
||||
|
||||
case 'App\Models\LicenseSeat':
|
||||
$pdf_view_route ='account.accept.accept-license-eula';
|
||||
$license = License::find($item->license_id);
|
||||
$display_model = $license->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\Component':
|
||||
$pdf_view_route ='account.accept.accept-component-eula';
|
||||
$component = Component::find($item->id);
|
||||
$display_model = $component->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\Consumable':
|
||||
$pdf_view_route ='account.accept.accept-consumable-eula';
|
||||
$consumable = Consumable::find($item->id);
|
||||
$display_model = $consumable->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
}
|
||||
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
|
||||
// $pdf_view_route ='account.accept.accept-asset-eula';
|
||||
// $asset_model = AssetModel::find($item->model_id);
|
||||
// $display_model = $asset_model->name;
|
||||
// $assigned_to = User::find($item->assigned_to)->present()->fullName;
|
||||
//
|
||||
// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
|
||||
// $pdf_view_route ='account.accept.accept-accessory-eula';
|
||||
// $accessory = Accessory::find($item->id);
|
||||
// $display_model = $accessory->name;
|
||||
// $assigned_to = User::find($item->assignedTo);
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* Gather the data for the PDF. We fire this whether there is a signature required or not,
|
||||
* since we want the moment-in-time proof of what the EULA was when they accepted it.
|
||||
*/
|
||||
$branding_settings = SettingsController::getPDFBranding();
|
||||
|
||||
if (is_null($branding_settings->logo)){
|
||||
$path_logo = "";
|
||||
} else {
|
||||
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'item_tag' => $item->asset_tag,
|
||||
'item_model' => $asset_model->name,
|
||||
'item_model' => $display_model,
|
||||
'item_serial' => $item->serial,
|
||||
'eula' => $item->getEula(),
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
|
||||
'assigned_to' => $assigned_to->first_name . ' ' . $assigned_to->last_name,
|
||||
'assigned_to' => $assigned_to,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'signature' => storage_path() . '/private_uploads/signatures/' . $sig_filename,
|
||||
'logo' => public_path() . '/uploads/' . $branding_settings->logo,
|
||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||
'logo' => $path_logo,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
];
|
||||
$pdf = Pdf::loadView('account.accept.accept-asset-eula', $data);
|
||||
Storage::put('private_uploads/eula-pdfs/' . $acceptance->stored_eula_file, $pdf->output());
|
||||
|
||||
$a = new Actionlog();
|
||||
$a->stored_eula = $item->getEula();
|
||||
$a->stored_eula_file = $acceptance->stored_eula_file;
|
||||
$a->save();
|
||||
if ($pdf_view_route!='') {
|
||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||
}
|
||||
|
||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename);
|
||||
event(new CheckoutAccepted($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
|
||||
} else {
|
||||
$acceptance->decline($sig_filename);
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
//
|
||||
$accessory_user= DB::table('checkout_acceptances')->find($acceptance->assigned_to_id);
|
||||
$assigned_to = User::find($accessory_user->assigned_to_id);
|
||||
$accessory_model = Accessory::find($item->id);
|
||||
$branding_settings = SettingsController::getPDFBranding();
|
||||
$data = [
|
||||
'item_tag' => $item->model_number,
|
||||
'item_model' => $accessory_model->name,
|
||||
'eula' => $item->getEula(),
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
|
||||
// 'assigned_by' => self
|
||||
'assigned_to' => $assigned_to->first_name . ' ' . $assigned_to->last_name,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'signature' => storage_path() . '/private_uploads/signatures/' . $sig_filename,
|
||||
'logo' => public_path() . '/uploads/' . $branding_settings->logo,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
];
|
||||
$pdf = Pdf::loadView('account.accept.accept-accessory-eula', $data);
|
||||
Storage::put('private_uploads/eula-pdfs/' . $acceptance->stored_eula_file, $pdf->output());
|
||||
|
||||
$a = new Actionlog();
|
||||
$a->stored_eula = $item->getEula();
|
||||
$a->stored_eula_file = $acceptance->stored_eula_file;
|
||||
$a->save();
|
||||
|
||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,7 @@ class AccessoriesController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', Accessory::class);
|
||||
$allowed_columns = ['id', 'name', 'model_number', 'eol', 'notes', 'created_at', 'min_amt', 'company_id'];
|
||||
|
||||
|
||||
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
|
||||
// Relations will be handled in query scopes a little further down.
|
||||
$allowed_columns =
|
||||
|
||||
@@ -35,7 +35,8 @@ class AssetMaintenancesController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$maintenances = AssetMaintenance::with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
|
||||
|
||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$maintenances = $maintenances->TextSearch($request->input('search'));
|
||||
@@ -45,6 +46,15 @@ class AssetMaintenancesController extends Controller
|
||||
$maintenances->where('asset_id', '=', $request->input('asset_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$maintenances->where('supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_maintenance_type')) {
|
||||
$maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type'));
|
||||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($maintenances) && ($request->get('offset') > $maintenances->count())) ? $maintenances->count() : $request->get('offset', 0);
|
||||
@@ -64,6 +74,7 @@ class AssetMaintenancesController extends Controller
|
||||
'asset_tag',
|
||||
'asset_name',
|
||||
'user_id',
|
||||
'supplier'
|
||||
];
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
@@ -72,6 +83,9 @@ class AssetMaintenancesController extends Controller
|
||||
case 'user_id':
|
||||
$maintenances = $maintenances->OrderAdmin($order);
|
||||
break;
|
||||
case 'supplier':
|
||||
$maintenances = $maintenances->OrderBySupplier($order);
|
||||
break;
|
||||
case 'asset_tag':
|
||||
$maintenances = $maintenances->OrderByTag($order);
|
||||
break;
|
||||
|
||||
@@ -70,6 +70,10 @@ class AssetModelsController extends Controller
|
||||
$assetmodels->onlyTrashed();
|
||||
}
|
||||
|
||||
if ($request->filled('category_id')) {
|
||||
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$assetmodels->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
@@ -544,11 +544,11 @@ class AssetsController extends Controller
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
// Set the field value based on what was sent in the request
|
||||
$field_val = $request->input($field->convertUnicodeDbSlug(), null);
|
||||
$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->convertUnicodeDbSlug().' is 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')));
|
||||
}
|
||||
@@ -563,13 +563,13 @@ class AssetsController extends Controller
|
||||
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->convertUnicodeDbSlug()));
|
||||
$field_val = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$asset->{$field->convertUnicodeDbSlug()} = $field_val;
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,13 +634,13 @@ class AssetsController extends Controller
|
||||
// Update custom fields
|
||||
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($request->has($field->convertUnicodeDbSlug())) {
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -714,30 +714,53 @@ class AssetsController extends Controller
|
||||
* @since [v5.1.18]
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function restore($assetId = null)
|
||||
public function restore(Request $request, $assetId = null)
|
||||
{
|
||||
// Get asset information
|
||||
$asset = Asset::withTrashed()->find($assetId);
|
||||
$this->authorize('delete', $asset);
|
||||
|
||||
if (isset($asset->id)) {
|
||||
// Restore the asset
|
||||
Asset::withTrashed()->where('id', $assetId)->restore();
|
||||
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_type = Asset::class;
|
||||
$logaction->item_id = $asset->id;
|
||||
$logaction->created_at = date("Y-m-d H:i:s");
|
||||
$logaction->user_id = Auth::user()->id;
|
||||
$logaction->logaction('restored');
|
||||
if ($asset->deleted_at=='') {
|
||||
$message = 'Asset was not deleted. No data was changed.';
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.restore.success')));
|
||||
} else {
|
||||
|
||||
$message = trans('admin/hardware/message.restore.success');
|
||||
// Restore the asset
|
||||
Asset::withTrashed()->where('id', $assetId)->restore();
|
||||
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_type = Asset::class;
|
||||
$logaction->item_id = $asset->id;
|
||||
$logaction->created_at = date("Y-m-d H:i:s");
|
||||
$logaction->user_id = Auth::user()->id;
|
||||
$logaction->logaction('restored');
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset, $request), $message));
|
||||
|
||||
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checkout an asset by its tag.
|
||||
*
|
||||
* @author [N. Butler]
|
||||
* @param string $tag
|
||||
* @since [v6.0.5]
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function checkoutByTag(AssetCheckoutRequest $request, $tag)
|
||||
{
|
||||
if ($asset = Asset::where('asset_tag', $tag)->first()) {
|
||||
return $this->checkout($request, $asset->id);
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkout an asset
|
||||
@@ -849,7 +872,7 @@ class AssetsController extends Controller
|
||||
$asset->assignedTo()->disassociate($asset);
|
||||
$asset->accepted = null;
|
||||
|
||||
if ($request->filled('name')) {
|
||||
if ($request->has('name')) {
|
||||
$asset->name = $request->input('name');
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,28 @@ class CategoriesController extends Controller
|
||||
$categories = $categories->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$categories->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('category_type')) {
|
||||
$categories->where('category_type', '=', $request->input('category_type'));
|
||||
}
|
||||
|
||||
if ($request->filled('use_default_eula')) {
|
||||
$categories->where('use_default_eula', '=', $request->input('use_default_eula'));
|
||||
}
|
||||
|
||||
if ($request->filled('require_acceptance')) {
|
||||
$categories->where('require_acceptance', '=', $request->input('require_acceptance'));
|
||||
}
|
||||
|
||||
if ($request->filled('checkin_email')) {
|
||||
$categories->where('checkin_email', '=', $request->input('checkin_email'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($categories) && ($request->get('offset') > $categories->count())) ? $categories->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -43,6 +43,11 @@ class CompaniesController extends Controller
|
||||
$companies->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$companies->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($companies) && ($request->get('offset') > $companies->count())) ? $companies->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -51,6 +51,10 @@ class ComponentsController extends Controller
|
||||
$components = $components->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$components->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$components->where('company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ class ConsumablesController extends Controller
|
||||
$consumables = $consumables->TextSearch(e($request->input('search')));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$consumables->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$consumables->where('company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,22 @@ class DepartmentsController extends Controller
|
||||
$departments = $departments->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$departments->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$departments->where('company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('manager_id')) {
|
||||
$departments->where('manager_id', '=', $request->input('manager_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$departments->where('location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($departments) && ($request->get('offset') > $departments->count())) ? $departments->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -28,6 +28,10 @@ class GroupsController extends Controller
|
||||
$groups = $groups->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$groups->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($groups) && ($request->get('offset') > $groups->count())) ? $groups->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -134,7 +134,14 @@ class ImportController extends Controller
|
||||
\Log::debug('NO BACKUP requested via importer');
|
||||
}
|
||||
|
||||
$errors = $request->import(Import::find($import_id));
|
||||
$import = Import::find($import_id);
|
||||
|
||||
if(is_null($import)){
|
||||
$error[0][0] = trans("validation.exists", ["attribute" => "file"]);
|
||||
return response()->json(Helper::formatStandardApiResponse('import-errors', null, $error), 500);
|
||||
}
|
||||
|
||||
$errors = $request->import($import);
|
||||
$redirectTo = 'hardware.index';
|
||||
switch ($request->get('import-type')) {
|
||||
case 'asset':
|
||||
|
||||
@@ -116,16 +116,20 @@ class LicenseSeatsController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||
}
|
||||
|
||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||
// we simply let assets take precedence over users...
|
||||
if ($licenseSeat->isDirty('assigned_to')) {
|
||||
$target = $is_checkin ? $oldUser : User::find($licenseSeat->assigned_to);
|
||||
}
|
||||
if ($licenseSeat->isDirty('asset_id')) {
|
||||
$target = $is_checkin ? $oldAsset : Asset::find($licenseSeat->asset_id);
|
||||
}
|
||||
|
||||
if (is_null($target)){
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
|
||||
}
|
||||
|
||||
if ($licenseSeat->save()) {
|
||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||
// we simply let assets take precedence over users...
|
||||
$changes = $licenseSeat->getChanges();
|
||||
if (array_key_exists('assigned_to', $changes)) {
|
||||
$target = $is_checkin ? $oldUser : User::find($changes['assigned_to']);
|
||||
}
|
||||
if (array_key_exists('asset_id', $changes)) {
|
||||
$target = $is_checkin ? $oldAsset : Asset::find($changes['asset_id']);
|
||||
}
|
||||
|
||||
if ($is_checkin) {
|
||||
$licenseSeat->logCheckin($target, $request->input('note'));
|
||||
|
||||
@@ -73,9 +73,6 @@ class LicensesController extends Controller
|
||||
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$licenses->where('supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
|
||||
$licenses->where('maintained','=',1);
|
||||
|
||||
@@ -53,6 +53,30 @@ class LocationsController extends Controller
|
||||
$locations = $locations->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$locations->where('locations.name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('address')) {
|
||||
$locations->where('locations.address', '=', $request->input('address'));
|
||||
}
|
||||
|
||||
if ($request->filled('address2')) {
|
||||
$locations->where('locations.address2', '=', $request->input('address2'));
|
||||
}
|
||||
|
||||
if ($request->filled('city')) {
|
||||
$locations->where('locations.city', '=', $request->input('city'));
|
||||
}
|
||||
|
||||
if ($request->filled('zip')) {
|
||||
$locations->where('locations.zip', '=', $request->input('zip'));
|
||||
}
|
||||
|
||||
if ($request->filled('country')) {
|
||||
$locations->where('locations.country', '=', $request->input('country'));
|
||||
}
|
||||
|
||||
$offset = (($locations) && (request('offset') > $locations->count())) ? $locations->count() : request('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
|
||||
@@ -37,6 +37,26 @@ class ManufacturersController extends Controller
|
||||
$manufacturers = $manufacturers->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$manufacturers->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('url')) {
|
||||
$manufacturers->where('url', '=', $request->input('url'));
|
||||
}
|
||||
|
||||
if ($request->filled('support_url')) {
|
||||
$manufacturers->where('support_url', '=', $request->input('support_url'));
|
||||
}
|
||||
|
||||
if ($request->filled('support_phone')) {
|
||||
$manufacturers->where('support_phone', '=', $request->input('support_phone'));
|
||||
}
|
||||
|
||||
if ($request->filled('support_email')) {
|
||||
$manufacturers->where('support_email', '=', $request->input('support_email'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($manufacturers) && ($request->get('offset') > $manufacturers->count())) ? $manufacturers->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -5,10 +5,37 @@ namespace App\Http\Controllers\Api;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\CheckoutRequest;
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Gate;
|
||||
use DB;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* The token repository implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokenRepository;
|
||||
|
||||
/**
|
||||
* Create a controller instance.
|
||||
*
|
||||
* @param \Laravel\Passport\TokenRepository $tokenRepository
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validation
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
|
||||
{
|
||||
$this->validation = $validation;
|
||||
$this->tokenRepository = $tokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of requested assets.
|
||||
*
|
||||
@@ -42,4 +69,90 @@ class ProfileController extends Controller
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete an API token
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function createApiToken(Request $request) {
|
||||
|
||||
if (!Gate::allows('self.api')) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$accessTokenName = $request->input('name', 'Auth Token');
|
||||
|
||||
if ($accessToken = Auth::user()->createToken($accessTokenName)->accessToken) {
|
||||
|
||||
// Get the ID so we can return that with the payload
|
||||
$token = DB::table('oauth_access_tokens')->where('user_id', '=', Auth::user()->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first();
|
||||
$accessTokenData['id'] = $token->id;
|
||||
$accessTokenData['token'] = $accessToken;
|
||||
$accessTokenData['name'] = $accessTokenName;
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $accessTokenData, 'Personal access token '.$accessTokenName.' created successfully'));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Token could not be created.'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete an API token
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function deleteApiToken($tokenId) {
|
||||
|
||||
if (!Gate::allows('self.api')) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$token = $this->tokenRepository->findForUser(
|
||||
$tokenId, Auth::user()->getAuthIdentifier()
|
||||
);
|
||||
|
||||
if (is_null($token)) {
|
||||
return new Response('', 404);
|
||||
}
|
||||
|
||||
$token->revoke();
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show user's API tokens
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function showApiTokens(Request $request) {
|
||||
|
||||
if (!Gate::allows('self.api')) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$tokens = $this->tokenRepository->forUser(Auth::user()->getAuthIdentifier());
|
||||
$token_values = $tokens->load('client')->filter(function ($token) {
|
||||
return $token->client->personal_access_client && ! $token->revoked;
|
||||
})->values();
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $token_values, null));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ class ReportsController extends Controller
|
||||
'accept_signature',
|
||||
'action_type',
|
||||
'note',
|
||||
'stored_eula_file',
|
||||
];
|
||||
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Transformers\DatatablesTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ldap;
|
||||
@@ -265,4 +268,52 @@ class SettingsController extends Controller
|
||||
|
||||
return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total);
|
||||
}
|
||||
|
||||
|
||||
public function listBackups() {
|
||||
$settings = Setting::getSettings();
|
||||
$path = 'app/backups';
|
||||
$backup_files = Storage::files($path);
|
||||
$files_raw = [];
|
||||
$count = 0;
|
||||
|
||||
if (count($backup_files) > 0) {
|
||||
|
||||
for ($f = 0; $f < count($backup_files); $f++) {
|
||||
|
||||
// Skip dotfiles like .gitignore and .DS_STORE
|
||||
if ((substr(basename($backup_files[$f]), 0, 1) != '.')) {
|
||||
$file_timestamp = Storage::lastModified($backup_files[$f]);
|
||||
|
||||
$files_raw[] = [
|
||||
'filename' => basename($backup_files[$f]),
|
||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||
'modified_value' => $file_timestamp,
|
||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||
|
||||
];
|
||||
$count++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$files = array_reverse($files_raw);
|
||||
return (new DatatablesTransformer)->transformDatatables($files, $count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function downloadBackup($file) {
|
||||
|
||||
$path = 'app/backups';
|
||||
if (Storage::exists($path.'/'.$file)) {
|
||||
$headers = ['ContentType' => 'application/zip'];
|
||||
return Storage::download($path.'/'.$file, $file, $headers);
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found'));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ class StatuslabelsController extends Controller
|
||||
$statuslabels = $statuslabels->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$statuslabels->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
|
||||
// if a status_type is passed, filter by that
|
||||
if ($request->filled('status_type')) {
|
||||
|
||||
@@ -34,6 +34,46 @@ class SuppliersController extends Controller
|
||||
$suppliers = $suppliers->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$suppliers->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
if ($request->filled('address')) {
|
||||
$suppliers->where('address', '=', $request->input('address'));
|
||||
}
|
||||
|
||||
if ($request->filled('address2')) {
|
||||
$suppliers->where('address2', '=', $request->input('address2'));
|
||||
}
|
||||
|
||||
if ($request->filled('city')) {
|
||||
$suppliers->where('city', '=', $request->input('city'));
|
||||
}
|
||||
|
||||
if ($request->filled('zip')) {
|
||||
$suppliers->where('zip', '=', $request->input('zip'));
|
||||
}
|
||||
|
||||
if ($request->filled('country')) {
|
||||
$suppliers->where('country', '=', $request->input('country'));
|
||||
}
|
||||
|
||||
if ($request->filled('fax')) {
|
||||
$suppliers->where('fax', '=', $request->input('fax'));
|
||||
}
|
||||
|
||||
if ($request->filled('email')) {
|
||||
$suppliers->where('email', '=', $request->input('email'));
|
||||
}
|
||||
|
||||
if ($request->filled('url')) {
|
||||
$suppliers->where('url', '=', $request->input('url'));
|
||||
}
|
||||
|
||||
if ($request->filled('notes')) {
|
||||
$suppliers->where('notes', '=', $request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($suppliers) && ($request->get('offset') > $suppliers->count())) ? $suppliers->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -36,6 +36,7 @@ class UsersController extends Controller
|
||||
|
||||
$users = User::select([
|
||||
'users.activated',
|
||||
'users.created_by',
|
||||
'users.address',
|
||||
'users.avatar',
|
||||
'users.city',
|
||||
@@ -66,7 +67,7 @@ class UsersController extends Controller
|
||||
'users.remote',
|
||||
'users.ldap_import',
|
||||
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables')
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
|
||||
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
|
||||
$users = Company::scopeCompanyables($users);
|
||||
|
||||
@@ -89,6 +90,10 @@ class UsersController extends Controller
|
||||
$users = $users->where('users.location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('created_by')) {
|
||||
$users = $users->where('users.created_by', '=', $request->input('created_by'));
|
||||
}
|
||||
|
||||
if ($request->filled('email')) {
|
||||
$users = $users->where('users.email', '=', $request->input('email'));
|
||||
}
|
||||
@@ -182,6 +187,9 @@ class UsersController extends Controller
|
||||
case 'department':
|
||||
$users = $users->OrderDepartment($order);
|
||||
break;
|
||||
case 'created_by':
|
||||
$users = $users->OrderByCreatedBy($order);
|
||||
break;
|
||||
case 'company':
|
||||
$users = $users->OrderCompany($order);
|
||||
break;
|
||||
@@ -519,10 +527,14 @@ class UsersController extends Controller
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$this->authorize('view', License::class);
|
||||
$user = User::where('id', $id)->withTrashed()->first();
|
||||
$licenses = $user->licenses()->get();
|
||||
|
||||
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
||||
$licenses = $user->licenses()->get();
|
||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||
|
||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Models\AssetModel;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Redirect;
|
||||
use Request;
|
||||
use Storage;
|
||||
@@ -90,7 +91,9 @@ class AssetModelsController extends Controller
|
||||
// Was it created?
|
||||
if ($model->save()) {
|
||||
if ($this->shouldAddDefaultValues($request->input())) {
|
||||
$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'));
|
||||
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to the new model page
|
||||
@@ -163,7 +166,9 @@ class AssetModelsController extends Controller
|
||||
$model->fieldset_id = $request->input('custom_fieldset');
|
||||
|
||||
if ($this->shouldAddDefaultValues($request->input())) {
|
||||
$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'));
|
||||
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +456,21 @@ class AssetModelsController extends Controller
|
||||
*/
|
||||
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues)
|
||||
{
|
||||
$data = array();
|
||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||
$customField = \App\Models\CustomField::find($customFieldId);
|
||||
|
||||
$data[$customField->db_column] = $defaultValue;
|
||||
}
|
||||
|
||||
$rules = $model->fieldset->validation_rules();
|
||||
|
||||
$validator = Validator::make($data, $rules);
|
||||
|
||||
if($validator->fails()){
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||
if(is_array($defaultValue)){
|
||||
$model->defaultValues()->attach($customFieldId, ['default_value' => implode(', ', $defaultValue)]);
|
||||
@@ -458,6 +478,7 @@ class AssetModelsController extends Controller
|
||||
$model->defaultValues()->attach($customFieldId, ['default_value' => $defaultValue]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\AssetFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\AssetModel;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
|
||||
class AssetModelsFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Upload a file to the server.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param AssetFileRequest $request
|
||||
* @param int $modelId
|
||||
* @return Redirect
|
||||
* @since [v1.0]
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(AssetFileRequest $request, $modelId = null)
|
||||
{
|
||||
if (! $model = AssetModel::find($modelId)) {
|
||||
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$this->authorize('update', $model);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/assetmodels')) {
|
||||
Storage::makeDirectory('private_uploads/assetmodels', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$file_name = 'model-'.$model->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/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('admin/hardware/message.upload.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for permissions and display the file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
* @return View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($modelId = null, $fileId = null, $download = true)
|
||||
{
|
||||
$model = AssetModel::find($modelId);
|
||||
// the asset is valid
|
||||
if (isset($model->id)) {
|
||||
$this->authorize('view', $model);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that model/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
||||
\Log::debug('Checking for '.$file);
|
||||
|
||||
|
||||
if (! Storage::exists($file)) {
|
||||
return response('File '.$file.' not found on server', 404)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
if ($download != 'true') {
|
||||
if ($contents = file_get_contents(Storage::url($file))) {
|
||||
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
|
||||
}
|
||||
|
||||
return JsonResponse::create(['error' => 'Failed validation: '], 500);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
}
|
||||
// Prepare the error message
|
||||
$error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]);
|
||||
|
||||
// Redirect to the hardware management page
|
||||
return redirect()->route('hardware.index')->with('error', $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associated file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
* @return View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($modelId = null, $fileId = null)
|
||||
{
|
||||
$model = AssetModel::find($modelId);
|
||||
$this->authorize('update', $model);
|
||||
$rel_path = 'private_uploads/assetmodels';
|
||||
|
||||
// the asset is valid
|
||||
if (isset($model->id)) {
|
||||
$this->authorize('update', $model);
|
||||
$log = Actionlog::find($fileId);
|
||||
if ($log) {
|
||||
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||
Storage::delete($rel_path.'/'.$log->filename);
|
||||
}
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the hardware management page
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
}
|
||||
@@ -98,9 +98,6 @@ class AssetCheckinController extends Controller
|
||||
}
|
||||
|
||||
$asset->location_id = $asset->rtd_location_id;
|
||||
\Log::debug('After Location ID: '.$asset->location_id);
|
||||
\Log::debug('After RTD Location ID: '.$asset->rtd_location_id);
|
||||
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
\Log::debug('NEW Location ID: '.$request->get('location_id'));
|
||||
|
||||
@@ -20,6 +20,7 @@ use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Input;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use League\Csv\Reader;
|
||||
@@ -167,17 +168,17 @@ class AssetsController extends Controller
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(implode(', ', $request->input($field->convertUnicodeDbSlug())));
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,18 +202,30 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$success = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
// Redirect to the asset listing page
|
||||
$minutes = 518400;
|
||||
// dd( $_POST['options']);
|
||||
// Cookie::queue(Cookie::make('optional_info', json_decode($_POST['options']), $minutes));
|
||||
return redirect()->route('hardware.index')
|
||||
->with('success', trans('admin/hardware/message.create.success'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||
}
|
||||
|
||||
public function getOptionCookie(Request $request){
|
||||
$value = $request->cookie('optional_info');
|
||||
echo $value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that presents a form to edit an existing asset.
|
||||
*
|
||||
@@ -343,17 +356,17 @@ class AssetsController extends Controller
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(implode(', ', $request->input($field->convertUnicodeDbSlug())));
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,6 @@ class BulkAssetsController extends Controller
|
||||
$bulk_back_url = request()->headers->get('referer');
|
||||
session(['bulk_back_url' => $bulk_back_url]);
|
||||
|
||||
\Log::debug('Back to url: '.$bulk_back_url);
|
||||
|
||||
|
||||
|
||||
$asset_ids = array_values(array_unique($request->input('ids')));
|
||||
|
||||
if ($request->filled('bulk_actions')) {
|
||||
|
||||
@@ -104,22 +104,19 @@ class LoginController extends Controller
|
||||
*/
|
||||
private function loginViaSaml(Request $request)
|
||||
{
|
||||
\Log::debug('Attempting to login via SAML');
|
||||
$saml = $this->saml;
|
||||
$samlData = $request->session()->get('saml_login');
|
||||
|
||||
if ($saml->isEnabled() && ! empty($samlData)) {
|
||||
\Log::debug('SAML is enabled, and the samleData is not empty');
|
||||
|
||||
try {
|
||||
Log::debug('Attempting to log user in by SAML authentication.');
|
||||
$user = $saml->samlLogin($samlData);
|
||||
|
||||
if (!is_null($user)) {
|
||||
Auth::login($user);
|
||||
} else {
|
||||
$username = $saml->getUsername();
|
||||
\Log::warning("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'));
|
||||
$saml->clearData();
|
||||
}
|
||||
@@ -130,7 +127,7 @@ class LoginController extends Controller
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::warning('There was an error authenticating the SAML user: '.$e->getMessage());
|
||||
\Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
|
||||
throw new \Exception($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -139,13 +136,12 @@ class LoginController extends Controller
|
||||
|
||||
// Better logging
|
||||
if (!$saml->isEnabled()) {
|
||||
\Log::warning("SAML page requested, but SAML does not seem to enabled.");
|
||||
\Log::debug("SAML page requested, but SAML does not seem to enabled.");
|
||||
} else {
|
||||
\Log::warning("SAML page requested, but samlData seems empty.");
|
||||
\Log::debug("SAML page requested, but samlData seems empty.");
|
||||
}
|
||||
}
|
||||
|
||||
\Log::warning("Something else went wrong while trying to login as SAML user");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\SaveUserRequest;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
@@ -63,6 +61,14 @@ class ResetPasswordController extends Controller
|
||||
|
||||
public function showResetForm(Request $request, $token = null)
|
||||
{
|
||||
|
||||
$credentials = $request->only('email', 'token');
|
||||
|
||||
if (is_null($this->broker()->getUser($credentials))) {
|
||||
\Log::debug('Password reset form FAILED - this token is not valid.');
|
||||
return redirect()->route('password.request')->with('error', trans('passwords.token'));
|
||||
}
|
||||
|
||||
return view('auth.passwords.reset')->with(
|
||||
[
|
||||
'token' => $token,
|
||||
@@ -73,38 +79,53 @@ class ResetPasswordController extends Controller
|
||||
|
||||
public function reset(Request $request)
|
||||
{
|
||||
|
||||
$broker = $this->broker();
|
||||
|
||||
$messages = [
|
||||
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
|
||||
];
|
||||
|
||||
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
||||
|
||||
// Check to see if the user even exists
|
||||
$user = User::where('username', '=', $request->input('username'))->first();
|
||||
\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
|
||||
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
|
||||
\Log::debug($user->username.' exists');
|
||||
|
||||
|
||||
// handle the password validation rules set by the admin settings
|
||||
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== false) {
|
||||
$request->validate(
|
||||
[
|
||||
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"',
|
||||
], $messages);
|
||||
}
|
||||
|
||||
|
||||
// set the response
|
||||
$response = $broker->reset(
|
||||
$this->credentials($request), function ($user, $password) {
|
||||
$this->resetPassword($user, $password);
|
||||
});
|
||||
|
||||
// Check if the password reset above actually worked
|
||||
if ($response == \Password::PASSWORD_RESET) {
|
||||
\Log::debug('Password reset for '.$user->username.' worked');
|
||||
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');
|
||||
return redirect()->back()->withInput($request->only('email'))->with('error', trans('passwords.token'));
|
||||
|
||||
$broker = $this->broker();
|
||||
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== false) {
|
||||
$request->validate(
|
||||
[
|
||||
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"',
|
||||
], $messages);
|
||||
}
|
||||
|
||||
$response = $broker->reset(
|
||||
$this->credentials($request), function ($user, $password) {
|
||||
$this->resetPassword($user, $password);
|
||||
}
|
||||
);
|
||||
|
||||
return $response == \Password::PASSWORD_RESET
|
||||
? $this->sendResetResponse($request, $response)
|
||||
: $this->sendResetFailedResponse($request, $response);
|
||||
\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'));
|
||||
|
||||
}
|
||||
|
||||
protected function sendResetFailedResponse(Request $request, $response)
|
||||
{
|
||||
return redirect()->back()
|
||||
->withInput(['username'=> $request->input('username')])
|
||||
->withErrors(['username' => trans($response), 'password' => trans($response)]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class ComponentsController extends Controller
|
||||
if (is_null($component = Component::find($componentId))) {
|
||||
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
|
||||
}
|
||||
$min = $component->numCHeckedOut();
|
||||
$min = $component->numCheckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
'qty' => "required|numeric|min:$min",
|
||||
]);
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Consumables for
|
||||
@@ -128,6 +129,17 @@ class ConsumablesController extends Controller
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$min = $consumable->numCheckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
"qty" => "required|numeric|min:$min"
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$this->authorize($consumable);
|
||||
|
||||
$consumable->name = $request->input('name');
|
||||
|
||||
@@ -211,23 +211,35 @@ class LocationsController extends Controller
|
||||
|
||||
public function print_assigned($id)
|
||||
{
|
||||
$location = Location::where('id', $id)->first();
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
|
||||
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
if ($location = Location::where('id', $id)->first()) {
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function print_all_assigned($id)
|
||||
{
|
||||
$location = Location::where('id', $id)->first();
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
|
||||
if ($location = Location::where('id', $id)->first()) {
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
|
||||
}
|
||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||
|
||||
|
||||
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,6 +642,10 @@ class ReportsController extends Controller
|
||||
if (($request->filled('next_audit_start')) && ($request->filled('next_audit_end'))) {
|
||||
$assets->whereBetween('assets.next_audit_date', [$request->input('next_audit_start'), $request->input('next_audit_end')]);
|
||||
}
|
||||
if($request->filled('exclude_archived')){
|
||||
$assets->notArchived();
|
||||
}
|
||||
|
||||
$assets->orderBy('assets.id', 'ASC')->chunk(20, function ($assets) use ($handle, $customfields, $request) {
|
||||
|
||||
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
|
||||
@@ -939,9 +943,9 @@ class ReportsController extends Controller
|
||||
* Get all assets with pending checkout acceptances
|
||||
*/
|
||||
if($showDeleted) {
|
||||
$acceptances = CheckoutAcceptance::pending()->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
} else {
|
||||
$acceptances = CheckoutAcceptance::pending()->with(['assignedTo' => function ($query) {
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->with(['assignedTo' => function ($query) {
|
||||
$query->withTrashed();
|
||||
}, 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
}
|
||||
@@ -1148,18 +1152,4 @@ class ReportsController extends Controller
|
||||
$this->getModelsInCategoriesThatRequireAcceptance($this->getCategoriesThatRequireAcceptance())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* getAssetsNotAcceptedYet
|
||||
*
|
||||
* @return array
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
*/
|
||||
protected function getAssetsNotAcceptedYet()
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
return Asset::unaccepted();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use Response;
|
||||
use App\Http\Requests\SlackSettingsRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Settings for
|
||||
@@ -910,7 +911,24 @@ class SettingsController extends Controller
|
||||
{
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
return view('settings.ldap', compact('setting'));
|
||||
/**
|
||||
* This validator is only temporary (famous last words.) - @snipe
|
||||
*/
|
||||
$messages = [
|
||||
'ldap_username_field.not_in' => '<code>sAMAccountName</code> (mixed case) will likely not work. You should use <code>samaccountname</code> (lowercase) instead. ',
|
||||
'ldap_auth_filter_query.not_in' => '<code>uid=samaccountname</code> is probably not a valid auth filter. You probably want <code>uid=</code> ',
|
||||
'ldap_filter.regex' => 'This value should probably not be wrapped in parentheses.',
|
||||
];
|
||||
|
||||
$validator = Validator::make($setting->toArray(), [
|
||||
'ldap_username_field' => 'not_in:sAMAccountName',
|
||||
'ldap_auth_filter_query' => 'not_in:uid=samaccountname',
|
||||
'ldap_filter' => 'regex:"^[^(]"',
|
||||
], $messages);
|
||||
|
||||
|
||||
|
||||
return view('settings.ldap', compact('setting'))->withErrors($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -942,7 +960,7 @@ class SettingsController extends Controller
|
||||
$setting->ldap_lname_field = $request->input('ldap_lname_field');
|
||||
$setting->ldap_fname_field = $request->input('ldap_fname_field');
|
||||
$setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query');
|
||||
$setting->ldap_version = $request->input('ldap_version');
|
||||
$setting->ldap_version = $request->input('ldap_version', 3);
|
||||
$setting->ldap_active_flag = $request->input('ldap_active_flag');
|
||||
$setting->ldap_emp_num = $request->input('ldap_emp_num');
|
||||
$setting->ldap_email = $request->input('ldap_email');
|
||||
@@ -1044,7 +1062,7 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function getBackups()
|
||||
{
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$path = 'app/backups';
|
||||
$backup_files = Storage::files($path);
|
||||
$files_raw = [];
|
||||
@@ -1061,7 +1079,7 @@ class SettingsController extends Controller
|
||||
'filename' => basename($backup_files[$f]),
|
||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||
'modified_value' => $file_timestamp,
|
||||
'modified_display' => Helper::getFormattedDateObject($file_timestamp, $type = 'datetime', false),
|
||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||
|
||||
];
|
||||
}
|
||||
@@ -1147,23 +1165,31 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function deleteFile($filename = null)
|
||||
{
|
||||
if (! config('app.lock_passwords')) {
|
||||
$path = 'app/backups';
|
||||
if (config('app.allow_backup_delete')=='true') {
|
||||
|
||||
if (Storage::exists($path.'/'.$filename)) {
|
||||
try {
|
||||
Storage::delete($path.'/'.$filename);
|
||||
if (!config('app.lock_passwords')) {
|
||||
$path = 'app/backups';
|
||||
|
||||
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted'));
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
if (Storage::exists($path . '/' . $filename)) {
|
||||
|
||||
try {
|
||||
Storage::delete($path . '/' . $filename);
|
||||
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted'));
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
} else {
|
||||
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
|
||||
}
|
||||
} else {
|
||||
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
|
||||
}
|
||||
} else {
|
||||
|
||||
return redirect()->route('settings.backups.index')->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
// Hell to the no
|
||||
\Log::warning('User ID '.Auth::user()->id.' is attempting to delete backup file '.$filename.' and is not authorized to.');
|
||||
return redirect()->route('settings.backups.index')->with('error', trans('general.backup_delete_not_allowed'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1198,9 +1224,10 @@ class SettingsController extends Controller
|
||||
Storage::putFileAs('app/backups', $request->file('file'), $upload_filename);
|
||||
|
||||
return redirect()->route('settings.backups.index')->with('success', 'File uploaded');
|
||||
} else {
|
||||
return redirect()->route('settings.backups.index')->withErrors($request->getErrors());
|
||||
}
|
||||
|
||||
return redirect()->route('settings.backups.index')->withErrors($request->getErrors());
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1234,7 +1261,11 @@ class SettingsController extends Controller
|
||||
// TODO: run a backup
|
||||
|
||||
|
||||
Artisan::call('db:wipe');
|
||||
Artisan::call('db:wipe', [
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
\Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
|
||||
|
||||
// run the restore command
|
||||
Artisan::call('snipeit:restore',
|
||||
@@ -1246,28 +1277,31 @@ class SettingsController extends Controller
|
||||
|
||||
// If it's greater than 300, it probably worked
|
||||
$output = Artisan::output();
|
||||
if (strlen($output) > 300) {
|
||||
$find_user = DB::table('users')->where('first_name', $user->first_name)->where('last_name', $user->last_name)->exists();
|
||||
if(!$find_user){
|
||||
\Log::warning('Attempting to restore user: ' . $user->first_name . ' ' . $user->last_name);
|
||||
$new_user = $user->replicate();
|
||||
$new_user->push();
|
||||
}
|
||||
|
||||
$session_files = glob(storage_path("framework/sessions/*"));
|
||||
foreach ($session_files as $file) {
|
||||
if (is_file($file))
|
||||
unlink($file);
|
||||
}
|
||||
DB::table('users')->update(['remember_token' => null]);
|
||||
\Auth::logout();
|
||||
/* Run migrations */
|
||||
\Log::debug('Migrating database...');
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
$migrate_output = Artisan::output();
|
||||
\Log::debug($migrate_output);
|
||||
|
||||
return redirect()->route('login')->with('success', 'Your system has been restored. Please login again.');
|
||||
$find_user = DB::table('users')->where('username', $user->username)->exists();
|
||||
|
||||
if (!$find_user){
|
||||
\Log::warning('Attempting to restore user: ' . $user->username);
|
||||
$new_user = $user->replicate();
|
||||
$new_user->push();
|
||||
} else {
|
||||
return redirect()->route('settings.backups.index')->with('error', $output);
|
||||
|
||||
\Log::debug('User: ' . $user->username .' already exists.');
|
||||
}
|
||||
|
||||
\Log::debug('Logging all users out..');
|
||||
Artisan::call('snipeit:global-logout', ['--force' => true]);
|
||||
|
||||
DB::table('users')->update(['remember_token' => null]);
|
||||
\Auth::logout();
|
||||
|
||||
return redirect()->route('login')->with('success', 'Your system has been restored. Please login again.');
|
||||
|
||||
} else {
|
||||
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
|
||||
}
|
||||
@@ -1287,9 +1321,15 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function getPurge()
|
||||
{
|
||||
\Log::warning('User ID '.Auth::user()->id.' is attempting a PURGE');
|
||||
|
||||
return view('settings.purge-form');
|
||||
\Log::warning('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting a PURGE');
|
||||
|
||||
if (config('app.allow_purge')=='true') {
|
||||
return view('settings.purge-form');
|
||||
}
|
||||
|
||||
return redirect()->route('settings.index')->with('error', trans('general.purge_not_allowed'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1303,22 +1343,40 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function postPurge(Request $request)
|
||||
{
|
||||
if (! config('app.lock_passwords')) {
|
||||
if ('DELETE' == $request->input('confirm_purge')) {
|
||||
\Log::warning('User ID '.Auth::user()->id.' initiated a PURGE!');
|
||||
// Run a backup immediately before processing
|
||||
Artisan::call('backup:run');
|
||||
Artisan::call('snipeit:purge', ['--force' => 'true', '--no-interaction' => true]);
|
||||
$output = Artisan::output();
|
||||
\Log::warning('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting a PURGE');
|
||||
|
||||
return view('settings/purge')
|
||||
->with('output', $output)->with('success', trans('admin/settings/message.purge.success'));
|
||||
if (config('app.allow_purge')=='true') {
|
||||
\Log::debug('Purging is not allowed via the .env');
|
||||
|
||||
if (!config('app.lock_passwords')) {
|
||||
|
||||
if ($request->input('confirm_purge')=='DELETE') {
|
||||
|
||||
\Log::warning('User ID ' . Auth::user()->id . ' initiated a PURGE!');
|
||||
// Run a backup immediately before processing
|
||||
Artisan::call('backup:run');
|
||||
Artisan::call('snipeit:purge', ['--force' => 'true', '--no-interaction' => true]);
|
||||
$output = Artisan::output();
|
||||
|
||||
return redirect()->route('settings.index')
|
||||
->with('output', $output)->with('success', trans('admin/settings/message.purge.success'));
|
||||
|
||||
} else {
|
||||
return redirect()->route('settings.purge.index')
|
||||
->with('error', trans('admin/settings/message.purge.validation_failed'));
|
||||
}
|
||||
} else {
|
||||
return redirect()->back()->with('error', trans('admin/settings/message.purge.validation_failed'));
|
||||
return redirect()->route('settings.index')
|
||||
->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
} else {
|
||||
return redirect()->back()->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
\Log::error('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting to purge deleted data and is not authorized to.');
|
||||
|
||||
|
||||
// Nope.
|
||||
return redirect()->route('settings.index')
|
||||
->with('error', trans('general.purge_not_allowed'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,8 +91,10 @@ class BulkUsersController extends Controller
|
||||
->conditionallyAddItem('company_id')
|
||||
->conditionallyAddItem('locale')
|
||||
->conditionallyAddItem('remote')
|
||||
->conditionallyAddItem('ldap_import')
|
||||
->conditionallyAddItem('activated');
|
||||
|
||||
|
||||
|
||||
// If the manager_id is one of the users being updated, generate a warning.
|
||||
if (array_search($request->input('manager_id'), $user_raw_array)) {
|
||||
$manager_conflict = true;
|
||||
@@ -107,7 +109,7 @@ class BulkUsersController extends Controller
|
||||
User::whereIn('id', $user_raw_array)
|
||||
->where('id', '!=', Auth::id())->update($this->update_array);
|
||||
|
||||
if(array_key_exists('location_id', $this->update_array)){
|
||||
if (array_key_exists('location_id', $this->update_array)){
|
||||
Asset::where('assigned_type', User::class)
|
||||
->whereIn('assigned_to', $user_raw_array)
|
||||
->update(['location_id' => $this->update_array['location_id']]);
|
||||
|
||||
@@ -23,6 +23,7 @@ use Redirect;
|
||||
use Str;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use View;
|
||||
use App\Notifications\CurrentInventory;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Users for
|
||||
@@ -116,6 +117,8 @@ class UsersController extends Controller
|
||||
$user->country = $request->input('country', null);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
$user->website = $request->input('website', null);
|
||||
$user->created_by = Auth::user()->id;
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
$permissions_array = $request->input('permission');
|
||||
@@ -266,6 +269,7 @@ class UsersController extends Controller
|
||||
$user->activated = $request->input('activated', 0);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
$user->website = $request->input('website', null);
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
@@ -612,6 +616,30 @@ class UsersController extends Controller
|
||||
->with('settings', Setting::getSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Emails user a list of assigned assets
|
||||
*
|
||||
* @author [G. Martinez] [<godmartinz@gmail.com>]
|
||||
* @since [v6.0.5]
|
||||
* @param \App\Http\Controllers\Users\UsersController $id
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function emailAssetList($id)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
|
||||
if (!$user = User::find($id)) {
|
||||
return redirect()->back()
|
||||
->with('error', trans('admin/users/message.user_not_found', ['id' => $id]));
|
||||
}
|
||||
if (empty($user->email)) {
|
||||
return redirect()->back()->with('error', trans('admin/users/message.user_has_no_email'));
|
||||
}
|
||||
|
||||
$user->notify((new CurrentInventory($user)));
|
||||
return redirect()->back()->with('success', trans('admin/users/general.user_notified'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send individual password reset email
|
||||
*
|
||||
@@ -636,4 +664,4 @@ class UsersController extends Controller
|
||||
|
||||
return redirect()->back()->with('error', 'User is not activated, is LDAP synced, or does not have an email address ');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,123 +180,4 @@ class ViewAssetsController extends Controller
|
||||
{
|
||||
return view('account/requested');
|
||||
}
|
||||
|
||||
// Get the acceptance screen
|
||||
public function getAcceptAsset($logID = null)
|
||||
{
|
||||
$findlog = Actionlog::where('id', $logID)->first();
|
||||
|
||||
if (! $findlog) {
|
||||
return redirect()->to('account/view-assets')->with('error', 'No matching record.');
|
||||
}
|
||||
|
||||
if ($findlog->accepted_id != '') {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
// TODO - Fix this for non-assets
|
||||
if (($findlog->item_type == Asset::class) && ($user->id != $findlog->item->assigned_to)) {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
$item = $findlog->item;
|
||||
|
||||
// Check if the asset exists
|
||||
if (is_null($item)) {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
} elseif (! Company::isCurrentUserHasAccess($item)) {
|
||||
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
|
||||
} else {
|
||||
return view('account/accept-asset', compact('item'))->with('findlog', $findlog)->with('item', $item);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the acceptance
|
||||
public function postAcceptAsset(Request $request, $logID = null)
|
||||
{
|
||||
|
||||
// Check if the asset exists
|
||||
if (is_null($findlog = Actionlog::where('id', $logID)->first())) {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
if ($findlog->accepted_id != '') {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
if ($request->missing('asset_acceptance')) {
|
||||
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
if (($findlog->item_type == Asset::class) && ($user->id != $findlog->item->assigned_to)) {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
if ($request->filled('signature_output')) {
|
||||
$path = config('app.private_uploads').'/signatures';
|
||||
$sig_filename = 'siglog-'.$findlog->id.'-'.date('Y-m-d-his').'.png';
|
||||
$data_uri = e($request->get('signature_output'));
|
||||
$encoded_image = explode(',', $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
|
||||
Storage::putFileAs($path, $decoded_image, $sig_filename);
|
||||
//file_put_contents($path.'/'.$sig_filename, $decoded_image);
|
||||
}
|
||||
|
||||
$logaction = new Actionlog();
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
$logaction_msg = 'accepted';
|
||||
$accepted = 'accepted';
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
} else {
|
||||
$logaction_msg = 'declined';
|
||||
$accepted = 'rejected';
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
$logaction->item_id = $findlog->item_id;
|
||||
$logaction->item_type = $findlog->item_type;
|
||||
|
||||
// Asset
|
||||
if (($findlog->item_id != '') && ($findlog->item_type == Asset::class)) {
|
||||
if ($request->input('asset_acceptance') != 'accepted') {
|
||||
DB::table('assets')
|
||||
->where('id', $findlog->item_id)
|
||||
->update(['assigned_to' => null]);
|
||||
}
|
||||
}
|
||||
|
||||
$logaction->target_id = $findlog->target_id;
|
||||
$logaction->target_type = User::class;
|
||||
$logaction->note = e($request->input('note'));
|
||||
$logaction->updated_at = date('Y-m-d H:i:s');
|
||||
|
||||
if (isset($sig_filename)) {
|
||||
$logaction->accept_signature = $sig_filename;
|
||||
}
|
||||
$log = $logaction->logaction($logaction_msg);
|
||||
|
||||
$update_checkout = DB::table('action_logs')
|
||||
->where('id', $findlog->id)
|
||||
->update(['accepted_id' => $logaction->id]);
|
||||
|
||||
if (($findlog->item_id != '') && ($findlog->item_type == Asset::class)) {
|
||||
$affected_asset = $logaction->item;
|
||||
$affected_asset->accepted = $accepted;
|
||||
$affected_asset->save();
|
||||
}
|
||||
|
||||
if ($update_checkout) {
|
||||
return redirect()->to('account/view-assets')->with('success', $return_msg);
|
||||
} else {
|
||||
return redirect()->to('account/view-assets')->with('error', 'Something went wrong ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +68,6 @@ class AccessoriesTransformer
|
||||
$array = [];
|
||||
|
||||
foreach ($accessory_users as $user) {
|
||||
\Log::debug(print_r($user->pivot, true));
|
||||
\Log::debug(print_r($user->pivot, true));
|
||||
$array[] = [
|
||||
|
||||
'assigned_pivot_id' => $user->pivot->id,
|
||||
|
||||
@@ -55,20 +55,35 @@ class ActionlogsTransformer
|
||||
}
|
||||
}
|
||||
|
||||
$file_url = '';
|
||||
if($actionlog->filename!='') {
|
||||
if ($actionlog->action_type == 'accepted') {
|
||||
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
|
||||
} else {
|
||||
if ($actionlog->itemType() == 'asset') {
|
||||
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'license') {
|
||||
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'user') {
|
||||
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => (int) $actionlog->id,
|
||||
'icon' => $icon,
|
||||
'file' => ($actionlog->filename!='') ?
|
||||
'file' => ($actionlog->filename!='')
|
||||
?
|
||||
[
|
||||
'url' => route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]),
|
||||
'url' => $file_url,
|
||||
'filename' => $actionlog->filename,
|
||||
'inlineable' => (bool) Helper::show_file_inline($actionlog->filename),
|
||||
] : null,
|
||||
|
||||
'item' => ($actionlog->item) ? [
|
||||
'id' => (int) $actionlog->item->id,
|
||||
'name' => ($actionlog->itemType()=='user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
|
||||
'name' => ($actionlog->itemType()=='user') ? e($actionlog->item->getFullNameAttribute()) : e($actionlog->item->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->itemType()),
|
||||
] : null,
|
||||
'location' => ($actionlog->location) ? [
|
||||
@@ -96,10 +111,10 @@ class ActionlogsTransformer
|
||||
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
|
||||
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
|
||||
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||
'stored_eula_file' => ($actionlog->stored_eula_file) ? route('log.storedeula.download', ['filename' => $actionlog->stored_eula_file]) : null,
|
||||
];
|
||||
//\Log::info("Clean Meta is: ".print_r($clean_meta,true));
|
||||
|
||||
//dd($array);
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,25 +94,40 @@ class AssetsTransformer
|
||||
$fields_array = [];
|
||||
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
if ($field->isFieldDecryptable($asset->{$field->convertUnicodeDbSlug()})) {
|
||||
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->convertUnicodeDbSlug()});
|
||||
if ($field->isFieldDecryptable($asset->{$field->db_column})) {
|
||||
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||
$value = (Gate::allows('superadmin')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
|
||||
if ($field->format == 'DATE'){
|
||||
if (Gate::allows('superadmin')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
} else {
|
||||
$value = strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
}
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->convertUnicodeDbSlug()),
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
|
||||
} else {
|
||||
$value = $asset->{$field->db_column};
|
||||
|
||||
if (($field->format == 'DATE') && (!is_null($value)) && ($value!='')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->convertUnicodeDbSlug()),
|
||||
'value' => e($asset->{$field->convertUnicodeDbSlug()}),
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
||||
$array['custom_fields'] = $fields_array;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -39,7 +39,7 @@ class ComponentsAssetsTransformer
|
||||
|
||||
if ($asset->model->fieldset) {
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
$fields_array = [$field->name => $asset->{$field->convertUnicodeDbSlug()}];
|
||||
$fields_array = [$field->name => $asset->{$field->db_column}];
|
||||
$array += $fields_array;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class CustomFieldsTransformer
|
||||
'field_values' => ($field->field_values) ? e($field->field_values) : null,
|
||||
'field_values_array' => ($field->field_values) ? explode("\r\n", e($field->field_values)) : null,
|
||||
'type' => e($field->element),
|
||||
'required' => $field->pivot ? $field->pivot->required : false,
|
||||
'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false,
|
||||
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -9,14 +9,14 @@ use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class DepreciationsTransformer
|
||||
{
|
||||
public function transformDepreciations(Collection $depreciations)
|
||||
public function transformDepreciations(Collection $depreciations, $total)
|
||||
{
|
||||
$array = [];
|
||||
foreach ($depreciations as $depreciation) {
|
||||
$array[] = self::transformDepreciation($depreciation);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array);
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformDepreciation(Depreciation $depreciation)
|
||||
@@ -27,8 +27,7 @@ class DepreciationsTransformer
|
||||
'months' => $depreciation->months.' '.trans('general.months'),
|
||||
'depreciation_min' => $depreciation->depreciation_min,
|
||||
'created_at' => Helper::getFormattedDateObject($depreciation->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime'),
|
||||
'depreciation_min' =>($depreciation->depreciation_min),
|
||||
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime')
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
@@ -40,4 +39,4 @@ class DepreciationsTransformer
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,10 @@ class UsersTransformer
|
||||
'accessories_count' => (int) $user->accessories_count,
|
||||
'consumables_count' => (int) $user->consumables_count,
|
||||
'company' => ($user->company) ? ['id' => (int) $user->company->id, 'name'=> e($user->company->name)] : null,
|
||||
'created_by' => ($user->createdBy) ? [
|
||||
'id' => (int) $user->createdBy->id,
|
||||
'name'=> e($user->createdBy->present()->fullName),
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($user->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($user->updated_at, 'datetime'),
|
||||
'last_login' => Helper::getFormattedDateObject($user->last_login, 'datetime'),
|
||||
|
||||
@@ -130,7 +130,7 @@ class AssetImporter extends ItemImporter
|
||||
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
|
||||
//-- the class that needs to use it (command importer or GUI importer inside the project).
|
||||
if (isset($target)) {
|
||||
$asset->fresh()->checkOut($target, $this->user_id);
|
||||
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WelcomeNotification;
|
||||
|
||||
@@ -60,6 +62,13 @@ class UserImporter extends ItemImporter
|
||||
if ($this->shouldUpdateField($user_department)) {
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($user_department);
|
||||
}
|
||||
|
||||
if (is_null($this->item['username']) || $this->item['username'] == "") {
|
||||
$user_full_name = $this->item['first_name'] . ' ' . $this->item['last_name'];
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_full_name, Setting::getSettings()->username_format);
|
||||
$this->item['username'] = $user_formatted_array['username'];
|
||||
}
|
||||
|
||||
$user = User::where('username', $this->item['username'])->first();
|
||||
if ($user) {
|
||||
if (! $this->updating) {
|
||||
@@ -71,6 +80,12 @@ class UserImporter extends ItemImporter
|
||||
$this->log('Updating User');
|
||||
$user->update($this->sanitizeItemForUpdating($user));
|
||||
$user->save();
|
||||
|
||||
// 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' => $user->location_id]);
|
||||
|
||||
// \Log::debug('UserImporter.php Updated User ' . print_r($user, true));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,13 @@ use Illuminate\Support\Facades\Notification;
|
||||
class CheckoutableListener
|
||||
{
|
||||
/**
|
||||
* Notify the user about the checked out checkoutable
|
||||
* Notify the user about the checked out checkoutable and add a record to the
|
||||
* checkout_requests table.
|
||||
*/
|
||||
public function onCheckedOut($event)
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
@@ -58,14 +61,12 @@ class CheckoutableListener
|
||||
*/
|
||||
public function onCheckedIn($event)
|
||||
{
|
||||
\Log::debug('checkin fired');
|
||||
\Log::debug('onCheckedIn in the Checkoutable listener fired');
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if (! $event->checkedOutTo instanceof User) {
|
||||
\Log::debug('checked out to not a user');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,16 +82,14 @@ class CheckoutableListener
|
||||
$acceptance->delete();
|
||||
}
|
||||
}
|
||||
\Log::debug('checked out to a user');
|
||||
|
||||
// Use default locale
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
\Log::debug('Use default settings locale');
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckinNotification($event)
|
||||
);
|
||||
} else {
|
||||
\Log::debug('Use user locale? I do not think this works as expected yet');
|
||||
// \Log::debug(print_r($this->getNotifiables($event), true));
|
||||
Notification::send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckinNotification($event)
|
||||
@@ -151,10 +150,6 @@ class CheckoutableListener
|
||||
private function getCheckinNotification($event)
|
||||
{
|
||||
|
||||
// $model = get_class($event->checkoutable);
|
||||
|
||||
|
||||
|
||||
$notificationClass = null;
|
||||
|
||||
switch (get_class($event->checkoutable)) {
|
||||
|
||||
@@ -22,24 +22,44 @@ use App\Models\LicenseSeat;
|
||||
|
||||
class LogListener
|
||||
{
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This one creates an action_logs entry for the checkin
|
||||
* @param CheckoutableCheckedIn $event
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event)
|
||||
{
|
||||
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date);
|
||||
}
|
||||
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This one creates an action_logs entry for the checkout
|
||||
*
|
||||
* @param CheckoutableCheckedOut $event
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
|
||||
{
|
||||
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout);
|
||||
}
|
||||
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This creates the entry in the action_logs table for the accept/decline action
|
||||
*/
|
||||
public function onCheckoutAccepted(CheckoutAccepted $event)
|
||||
{
|
||||
|
||||
\Log::debug('event passed to the onCheckoutAccepted listener:');
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item()->associate($event->acceptance->checkoutable);
|
||||
$logaction->target()->associate($event->acceptance->assignedTo);
|
||||
$logaction->accept_signature = $event->acceptance->signature_filename;
|
||||
$logaction->stored_eula_file = $event->acceptance->stored_eula_file;
|
||||
$logaction->filename = $event->acceptance->stored_eula_file;
|
||||
$logaction->action_type = 'accepted';
|
||||
|
||||
// TODO: log the actual license seat that was checked out
|
||||
@@ -47,6 +67,7 @@ class LogListener
|
||||
$logaction->item()->associate($event->acceptance->checkoutable->license);
|
||||
}
|
||||
|
||||
\Log::debug('New onCheckoutAccepted Listener fired. logaction: '.print_r($logaction, true));
|
||||
$logaction->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -310,6 +310,21 @@ class Accessory extends SnipeModel
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items within an accessory are checked out
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
* @return int
|
||||
*/
|
||||
public function numCheckedOut()
|
||||
{
|
||||
$checkedout = 0;
|
||||
$checkedout = $this->users->count();
|
||||
|
||||
return $checkedout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items of an accessory remain
|
||||
*
|
||||
|
||||
@@ -25,7 +25,7 @@ class Actionlog extends SnipeModel
|
||||
|
||||
protected $table = 'action_logs';
|
||||
public $timestamps = true;
|
||||
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type', 'stored_eula', 'stored_eula_file'];
|
||||
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type', 'stored_eula'];
|
||||
|
||||
use Searchable;
|
||||
|
||||
|
||||
+28
-1
@@ -1147,6 +1147,31 @@ class Asset extends Depreciable
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope for Archived assets counting
|
||||
*
|
||||
* This is primarily used for the tab counters so that IF the admin
|
||||
* has chosen to not display archived assets in their regular lists
|
||||
* and views, it will return the correct number.
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
|
||||
public function scopeAssetsForShow($query)
|
||||
{
|
||||
|
||||
if (Setting::getSettings()->show_archived_in_list!=1) {
|
||||
return $query->whereHas('assetstatus', function ($query) {
|
||||
$query->where('archived', '=', 0);
|
||||
});
|
||||
} else {
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope for Archived assets
|
||||
*
|
||||
@@ -1187,7 +1212,9 @@ class Asset extends Depreciable
|
||||
|
||||
public function scopeRequestableAssets($query)
|
||||
{
|
||||
return Company::scopeCompanyables($query->where('requestable', '=', 1))
|
||||
$table = $query->getModel()->getTable();
|
||||
|
||||
return Company::scopeCompanyables($query->where($table.'.requestable', '=', 1))
|
||||
->whereHas('assetstatus', function ($query) {
|
||||
$query->where(function ($query) {
|
||||
$query->where('deployable', '=', 1)
|
||||
|
||||
@@ -162,6 +162,20 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||
* -----------------------------------------------
|
||||
**/
|
||||
|
||||
/**
|
||||
* Query builder scope to order on a supplier
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param string $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderBySupplier($query, $order)
|
||||
{
|
||||
return $query->leftJoin('suppliers as suppliers_maintenances', 'asset_maintenances.supplier_id', '=', 'suppliers_maintenances.id')
|
||||
->orderBy('suppliers_maintenances.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on admin user
|
||||
*
|
||||
|
||||
@@ -20,7 +20,7 @@ class AssetModel extends SnipeModel
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
protected $presenter = \App\Presenters\AssetModelPresenter::class;
|
||||
use Requestable, Presentable;
|
||||
use Loggable, Requestable, Presentable;
|
||||
|
||||
protected $table = 'models';
|
||||
protected $hidden = ['user_id', 'deleted_at'];
|
||||
@@ -181,6 +181,23 @@ class AssetModel extends SnipeModel
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uploads for this model
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v4.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function uploads()
|
||||
{
|
||||
return $this->hasMany('\App\Models\Actionlog', 'item_id')
|
||||
->where('item_type', '=', AssetModel::class)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->whereNotNull('filename')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* -----------------------------------------------
|
||||
* BEGIN QUERY SCOPES
|
||||
|
||||
@@ -57,20 +57,24 @@ class CheckoutAcceptance extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept the checkout acceptance
|
||||
* Add a record to the checkout_acceptance table ONLY.
|
||||
* Do not add stuff here that doesn't have a corresponding column in the
|
||||
* checkout_acceptances table or you'll get an error.
|
||||
*
|
||||
* @param string $signature_filename
|
||||
*/
|
||||
public function accept($signature_filename)
|
||||
public function accept($signature_filename, $eula = null, $filename = null)
|
||||
{
|
||||
$this->accepted_at = now();
|
||||
$this->signature_filename = $signature_filename;
|
||||
$this->stored_eula = $eula;
|
||||
$this->stored_eula_file = $filename;
|
||||
$this->save();
|
||||
|
||||
/**
|
||||
* Update state for the checked out item
|
||||
*/
|
||||
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename);
|
||||
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -276,6 +276,21 @@ class Consumable extends SnipeModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items within a consumable are checked out
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
* @return int
|
||||
*/
|
||||
public function numCheckedOut()
|
||||
{
|
||||
$checkedout = 0;
|
||||
$checkedout = $this->users->count();
|
||||
|
||||
return $checkedout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the number of available consumables
|
||||
*
|
||||
|
||||
@@ -111,7 +111,7 @@ class CustomField extends Model
|
||||
|
||||
// Column already exists on the assets table - nothing to do here.
|
||||
// This *shouldn't* happen in the wild.
|
||||
if (Schema::hasColumn(self::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
||||
if (Schema::hasColumn(self::$table_name, $custom_field->db_column)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class CustomField extends Model
|
||||
// Drop the assets column if we've deleted it from custom fields
|
||||
self::deleting(function ($custom_field) {
|
||||
return Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
||||
$table->dropColumn($custom_field->convertUnicodeDbSlug());
|
||||
$table->dropColumn($custom_field->db_column);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,16 +66,11 @@ class Depreciable extends SnipeModel
|
||||
/**
|
||||
* @return float|int
|
||||
*/
|
||||
public function getLinearDepreciatedValue()
|
||||
public function getLinearDepreciatedValue() // TODO - for testing it might be nice to have an optional $relative_to param here, defaulted to 'now'
|
||||
{
|
||||
$numerator= (($this->purchase_cost-($this->purchase_cost*12/($this->get_depreciation()->months))));
|
||||
$denominator=$this->get_depreciation()->months/12;
|
||||
$deprecation_per_year= $numerator/$denominator;
|
||||
$deprecation_per_month= $deprecation_per_year/12;
|
||||
|
||||
$months_remaining = $this->time_until_depreciated()->m + 12 * $this->time_until_depreciated()->y; //UGlY
|
||||
$months_depreciated=$this->get_depreciation()->months-$months_remaining;
|
||||
$current_value = $this->purchase_cost-($deprecation_per_month*$months_depreciated);
|
||||
|
||||
$current_value = round(($months_remaining / $this->get_depreciation()->months) * $this->purchase_cost, 2);
|
||||
|
||||
if($this->get_depreciation()->depreciation_min > $current_value) {
|
||||
|
||||
|
||||
+9
-7
@@ -37,7 +37,7 @@ class Ldap extends Model
|
||||
public static function connectToLdap()
|
||||
{
|
||||
$ldap_host = Setting::getSettings()->ldap_server;
|
||||
$ldap_version = Setting::getSettings()->ldap_version;
|
||||
$ldap_version = Setting::getSettings()->ldap_version ?: 3;
|
||||
$ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore;
|
||||
$ldap_use_tls = Setting::getSettings()->ldap_tls;
|
||||
|
||||
@@ -64,8 +64,8 @@ class Ldap extends Model
|
||||
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
|
||||
|
||||
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
|
||||
ldap_set_option($connection, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
||||
ldap_set_option($connection, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
||||
ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
||||
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
||||
}
|
||||
|
||||
if ($ldap_use_tls=='1') {
|
||||
@@ -275,9 +275,10 @@ class Ldap extends Model
|
||||
* @since [v3.0]
|
||||
* @param $base_dn
|
||||
* @param $count
|
||||
* @param $filter
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function findLdapUsers($base_dn = null, $count = -1)
|
||||
public static function findLdapUsers($base_dn = null, $count = -1, $filter = null)
|
||||
{
|
||||
$ldapconn = self::connectToLdap();
|
||||
self::bindAdminToLdap($ldapconn);
|
||||
@@ -285,7 +286,9 @@ class Ldap extends Model
|
||||
if (is_null($base_dn)) {
|
||||
$base_dn = Setting::getSettings()->ldap_basedn;
|
||||
}
|
||||
$filter = Setting::getSettings()->ldap_filter;
|
||||
if($filter === null) {
|
||||
$filter = Setting::getSettings()->ldap_filter;
|
||||
}
|
||||
|
||||
// Set up LDAP pagination for very large databases
|
||||
$page_size = 500;
|
||||
@@ -304,14 +307,13 @@ class Ldap extends Model
|
||||
|
||||
// HUGE thanks to this article: https://stackoverflow.com/questions/68275972/how-to-get-paged-ldap-queries-in-php-8-and-read-more-than-1000-entries
|
||||
// which helped me wrap my head around paged results!
|
||||
\Log::info("ldap conn is: ".$ldapconn." basedn is: $base_dn, filter is: $filter - count is: $count. page size is: $page_size"); //FIXME - remove
|
||||
// if a $count is set and it's smaller than $page_size then use that as the page size
|
||||
$ldap_controls = [];
|
||||
//if($count == -1) { //count is -1 means we have to employ paging to query the entire directory
|
||||
$ldap_controls = [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'iscritical' => false, 'value' => ['size'=> $count == -1||$count>$page_size ? $page_size : $count, 'cookie' => $cookie]]];
|
||||
//}
|
||||
$search_results = ldap_search($ldapconn, $base_dn, $filter, [], 0, /* $page_size */ -1, -1, LDAP_DEREF_NEVER, $ldap_controls); // TODO - I hate the @, and I hate that we get a full page even if we ask for 10 records. Can we use an ldap_control?
|
||||
\Log::info("did the search run? I guess so if you got here!");
|
||||
\Log::debug("LDAP search executed successfully.");
|
||||
if (! $search_results) {
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // TODO this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ class Location extends SnipeModel
|
||||
return $this->hasMany(\App\Models\User::class, 'location_id');
|
||||
}
|
||||
|
||||
|
||||
public function assets()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Asset::class, 'location_id')
|
||||
@@ -129,6 +130,23 @@ class Location extends SnipeModel
|
||||
return $this->hasMany(\App\Models\Asset::class, 'rtd_location_id');
|
||||
}
|
||||
|
||||
public function consumables()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Consumable::class, 'location_id');
|
||||
}
|
||||
|
||||
public function components()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Component::class, 'location_id');
|
||||
}
|
||||
|
||||
public function accessories()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Accessory::class, 'location_id');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(self::class, 'parent_id', 'id')
|
||||
|
||||
@@ -218,6 +218,7 @@ class Setting extends Model
|
||||
*/
|
||||
public static function fileSizeConvert($bytes): string
|
||||
{
|
||||
$result = 0;
|
||||
$bytes = floatval($bytes);
|
||||
$arBytes = [
|
||||
0 => [
|
||||
|
||||
@@ -42,7 +42,7 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
);
|
||||
|
||||
$config['validations'][$core.'emails'] = 'nullable|array'; // emails are not required in Snipe-IT...
|
||||
$config['validations'][$core.'emails.*.value'] = 'required|email'; // ...but if you give us one, it better be an email address
|
||||
$config['validations'][$core.'emails.*.value'] = 'email'; // ...(had to remove the recommended 'required' here)
|
||||
|
||||
$mappings['emails'] = [[
|
||||
"value" => AttributeMapping::eloquent("email"),
|
||||
@@ -58,7 +58,7 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
|
||||
//phone
|
||||
$config['validations'][$core.'phoneNumbers'] = 'nullable|array';
|
||||
$config['validations'][$core.'phoneNumbers.*.value'] = 'required';
|
||||
$config['validations'][$core.'phoneNumbers.*.value'] = 'string'; // another one where want to say 'we don't _need_ a phone number, but if you have one it better have a value.
|
||||
|
||||
$mappings['phoneNumbers'] = [[
|
||||
"value" => AttributeMapping::eloquent("phone"),
|
||||
@@ -69,10 +69,10 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
|
||||
//address
|
||||
$config['validations'][$core.'addresses'] = 'nullable|array';
|
||||
$config['validations'][$core.'addresses.*.streetAddress'] = 'required';
|
||||
$config['validations'][$core.'addresses.*.streetAddress'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.locality'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.region'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.postalCode'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.region'] = 'nullable|string';
|
||||
$config['validations'][$core.'addresses.*.postalCode'] = 'nullable|string';
|
||||
$config['validations'][$core.'addresses.*.country'] = 'string';
|
||||
|
||||
$mappings['addresses'] = [[
|
||||
@@ -118,7 +118,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
'employeeNumber' => AttributeMapping::eloquent('employee_num'),
|
||||
'department' =>(new AttributeMapping())->setAdd( // FIXME parent?
|
||||
function ($value, &$object) {
|
||||
\Log::error("Department-Add: $value"); //FIXME
|
||||
$department = Department::where("name", $value)->first();
|
||||
if ($department) {
|
||||
$object->department_id = $department->id;
|
||||
@@ -126,7 +125,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
}
|
||||
)->setReplace(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Department-Replace: $value"); //FIXME
|
||||
$department = Department::where("name", $value)->first();
|
||||
if ($department) {
|
||||
$object->department_id = $department->id;
|
||||
@@ -134,7 +132,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
}
|
||||
)->setRead(
|
||||
function (&$object) {
|
||||
\Log::error("Weird department reader firing..."); //FIXME
|
||||
return $object->department ? $object->department->name : null;
|
||||
}
|
||||
),
|
||||
@@ -145,7 +142,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
// NOTE: you could probably do a 'plain' Eloquent mapping here, but we don't for future-proofing
|
||||
'value' => (new AttributeMapping())->setAdd(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Manager-Add: $value"); //FIXME
|
||||
$manager = User::find($value);
|
||||
if ($manager) {
|
||||
$object->manager_id = $manager->id;
|
||||
@@ -153,7 +149,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
}
|
||||
)->setReplace(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Manager-Replace: $value"); //FIXME
|
||||
$manager = User::find($value);
|
||||
if ($manager) {
|
||||
$object->manager_id = $manager->id;
|
||||
@@ -161,7 +156,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
}
|
||||
)->setRead(
|
||||
function (&$object) {
|
||||
\Log::error("Weird manager reader firing..."); //FIXME
|
||||
return $object->manager_id;
|
||||
}
|
||||
),
|
||||
|
||||
@@ -184,7 +184,7 @@ class Supplier extends SnipeModel
|
||||
*/
|
||||
public function addhttp($url)
|
||||
{
|
||||
if (! preg_match('~^(?:f|ht)tps?://~i', $url)) {
|
||||
if (($url!='') && (! preg_match('~^(?:f|ht)tps?://~i', $url))) {
|
||||
$url = 'http://'.$url;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ trait Acceptable
|
||||
* @param User $acceptedBy
|
||||
* @param string $signature
|
||||
*/
|
||||
public function acceptedCheckout(User $acceptedBy, $signature)
|
||||
public function acceptedCheckout(User $acceptedBy, $signature, $filename = null)
|
||||
{
|
||||
\Log::debug('acceptedCheckout in Acceptable trait fired, tho it doesn\'t do anything?');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -561,6 +561,18 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin user who created this user
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function createdBy()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\User::class, 'created_by')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether two-factor authorization is required and the user has activated it
|
||||
* and enrolled a device
|
||||
@@ -685,6 +697,23 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return $query->leftJoin('departments as departments_users', 'users.department_id', '=', 'departments_users.id')->orderBy('departments_users.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on admin user
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param string $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderByCreatedBy($query, $order)
|
||||
{
|
||||
// Left join here, or it will only return results with parents
|
||||
return $query->leftJoin('users as admin_user', 'users.created_by', '=', 'admin_user.id')
|
||||
->orderBy('admin_user.first_name', $order)
|
||||
->orderBy('admin_user.last_name', $order);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope to order on company
|
||||
*
|
||||
|
||||
@@ -54,7 +54,6 @@ class CheckinAssetNotification extends Notification
|
||||
* has the corresponding checkbox checked.
|
||||
*/
|
||||
if ($this->item->checkin_email() && $this->target instanceof User && $this->target->email != '') {
|
||||
\Log::debug('use email');
|
||||
$notifyBy[] = 'mail';
|
||||
}
|
||||
|
||||
|
||||
@@ -18,22 +18,37 @@ class AssetObserver
|
||||
public function updating(Asset $asset)
|
||||
{
|
||||
$attributes = $asset->getAttributes();
|
||||
$attributesOriginal = $asset->getOriginal();
|
||||
|
||||
$attributesOriginal = $asset->getRawOriginal();
|
||||
$same_checkout_counter = false;
|
||||
$same_checkin_counter = false;
|
||||
|
||||
if (array_key_exists('checkout_counter', $attributes) && array_key_exists('checkout_counter', $attributesOriginal)){
|
||||
$same_checkout_counter = (($attributes['checkout_counter'] == $attributesOriginal['checkout_counter']));
|
||||
}
|
||||
|
||||
if (array_key_exists('checkin_counter', $attributes) && array_key_exists('checkin_counter', $attributesOriginal)){
|
||||
$same_checkin_counter = (($attributes['checkin_counter'] == $attributesOriginal['checkin_counter']));
|
||||
}
|
||||
|
||||
// If the asset isn't being checked out or audited, log the update.
|
||||
// (Those other actions already create log entries.)
|
||||
if (($attributes['assigned_to'] == $attributesOriginal['assigned_to'])
|
||||
if (($attributes['assigned_to'] == $attributesOriginal['assigned_to'])
|
||||
&& ($same_checkout_counter) && ($same_checkin_counter)
|
||||
&& ((isset( $attributes['next_audit_date']) ? $attributes['next_audit_date'] : null) == (isset($attributesOriginal['next_audit_date']) ? $attributesOriginal['next_audit_date']: null))
|
||||
&& ($attributes['last_checkout'] == $attributesOriginal['last_checkout']))
|
||||
&& ($attributes['last_checkout'] == $attributesOriginal['last_checkout']))
|
||||
{
|
||||
$changed = [];
|
||||
|
||||
foreach ($asset->getOriginal() as $key => $value) {
|
||||
if ($asset->getOriginal()[$key] != $asset->getAttributes()[$key]) {
|
||||
$changed[$key]['old'] = $asset->getOriginal()[$key];
|
||||
foreach ($asset->getRawOriginal() as $key => $value) {
|
||||
if ($asset->getRawOriginal()[$key] != $asset->getAttributes()[$key]) {
|
||||
$changed[$key]['old'] = $asset->getRawOriginal()[$key];
|
||||
$changed[$key]['new'] = $asset->getAttributes()[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($changed)){
|
||||
return;
|
||||
}
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Asset::class;
|
||||
|
||||
@@ -248,7 +248,7 @@ class AssetAuditPresenter extends Presenter
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$layout[] = [
|
||||
'field' => 'custom_fields.'.$field->convertUnicodeDbSlug(),
|
||||
'field' => 'custom_fields.'.$field->db_column,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
|
||||
@@ -263,7 +263,7 @@ class AssetPresenter extends Presenter
|
||||
// name can break the listings page. - snipe
|
||||
foreach ($fields as $field) {
|
||||
$layout[] = [
|
||||
'field' => 'custom_fields.'.$field->convertUnicodeDbSlug(),
|
||||
'field' => 'custom_fields.'.$field->db_column,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
|
||||
@@ -48,13 +48,7 @@ class DepreciationReportPresenter extends Presenter
|
||||
"sortable" => true,
|
||||
"title" => trans('general.asset_model'),
|
||||
"visible" => true,
|
||||
], [
|
||||
"field" => "model",
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
"title" => trans('admin/hardware/form.model'),
|
||||
"visible" => true,
|
||||
], [
|
||||
], [
|
||||
"field" => "model_number",
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
|
||||
@@ -90,6 +90,14 @@ class LocationPresenter extends Presenter
|
||||
'title' => trans('admin/locations/table.address'),
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'field' => 'address2',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/locations/table.address'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'city',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -285,6 +285,14 @@ class UserPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'created_by',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.created_by'),
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'created_at',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -40,7 +40,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
if (strpos(env('APP_URL'), 'https') === 0) {
|
||||
$url->forceScheme('https');
|
||||
} else {
|
||||
\Log::warning("'APP_FORCE_TLS' is set to true, but 'APP_URL' does not start with 'https://'. Will not force TLS on connections.");
|
||||
\Log::debug("'APP_FORCE_TLS' is set to true, but 'APP_URL' does not start with 'https://'. Will not force TLS on connections.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,12 +75,22 @@ class RouteServiceProvider extends ServiceProvider
|
||||
/**
|
||||
* Configure the rate limiters for the application.
|
||||
*
|
||||
* https://laravel.com/docs/8.x/routing#rate-limiting
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureRateLimiting()
|
||||
{
|
||||
|
||||
// Rate limiter for API calls
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
|
||||
return Limit::perMinute(config('app.api_throttle_per_minute'))->by(optional($request->user())->id ?: $request->ip());
|
||||
});
|
||||
|
||||
// Rate limiter for forgotten password requests
|
||||
RateLimiter::for('forgotten_password', function (Request $request) {
|
||||
return Limit::perMinute(config('auth.password_reset.max_attempts_per_min'))->by(optional($request->user())->id ?: $request->ip());
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,11 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
|
||||
// Model paths and URLs
|
||||
|
||||
|
||||
\App::singleton('eula_pdf_path', function () {
|
||||
return 'eula_pdf_path/';
|
||||
});
|
||||
|
||||
\App::singleton('assets_upload_path', function () {
|
||||
return 'assets/';
|
||||
});
|
||||
|
||||
@@ -130,11 +130,12 @@ class Saml
|
||||
$this->clearData();
|
||||
}
|
||||
|
||||
\Log::debug('Trying to create a new OneLogin_Saml2_Auth object ');
|
||||
try {
|
||||
$this->_auth = new OneLogin_Saml2_Auth($this->_settings);
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Trying OneLogin_Saml2_Auth failed. Setting SAML enabled to false. OneLogin_Saml2_Auth error message is: '. $e->getMessage());
|
||||
if ( $this->isEnabled() ) { // $this->loadSettings() initializes this to true if SAML is enabled by settings.
|
||||
\Log::warning('Trying OneLogin_Saml2_Auth failed. Setting SAML enabled to false. OneLogin_Saml2_Auth error message is: '. $e->getMessage());
|
||||
}
|
||||
$this->_enabled = false;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +158,6 @@ class Saml
|
||||
$this->_enabled = $setting->saml_enabled == '1';
|
||||
|
||||
if ($this->isEnabled()) {
|
||||
\Log::debug('SAML is enabled according to loadSettings()');
|
||||
//Let onelogin/php-saml know to use 'X-Forwarded-*' headers if it is from a trusted proxy
|
||||
OneLogin_Saml2_Utils::setProxyVars(request()->isFromTrustedProxy());
|
||||
|
||||
|
||||
+6
-6
@@ -11,13 +11,13 @@
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"type": "project",
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/grokability/laravel-scim-server"
|
||||
}
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/grokability/laravel-scim-server"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4 <8.1",
|
||||
"php": ">=7.4 <8.3",
|
||||
"ext-curl": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-json": "*",
|
||||
@@ -127,4 +127,4 @@
|
||||
"discard-changes": true,
|
||||
"process-timeout": 3000
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+469
-292
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user