Compare commits
655 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8231bc338 | |||
| 4d25e8f7f0 | |||
| 8368576dc9 | |||
| 071b4d1e67 | |||
| 1fe170e6a1 | |||
| 612a708c8d | |||
| 580a4c476e | |||
| c9de9ebbab | |||
| 3d0770973a | |||
| e814cd5a9e | |||
| e5f426ec64 | |||
| a1b0a30351 | |||
| c0f0f43dd7 | |||
| 57c07a3687 | |||
| 6de08f46fd | |||
| 3554270366 | |||
| 029450bcbf | |||
| 329fbf6a7c | |||
| b7d0fccabc | |||
| 48ab94c15b | |||
| ac907add83 | |||
| 3d47a8ba50 | |||
| 452185be45 | |||
| 14feed61d8 | |||
| 02a8e17704 | |||
| 7553ec3e27 | |||
| c8f82cbc2b | |||
| b7bd56daf7 | |||
| 393118f083 | |||
| d3210c6d40 | |||
| 60d7232569 | |||
| 2f1212fa1a | |||
| cc4d8f2a5b | |||
| c0a3284fad | |||
| caff608e3c | |||
| c48fa7c2cb | |||
| 14b25949b8 | |||
| 2df995c2c7 | |||
| ad182a96fa | |||
| a728f38bd1 | |||
| 894754e8dc | |||
| d141675478 | |||
| 8bdd80e236 | |||
| c422737525 | |||
| fc55786ca2 | |||
| 2949fdecdd | |||
| d32163f881 | |||
| 215fe501ac | |||
| ef3112e526 | |||
| 8aa0135afa | |||
| ff1157a95e | |||
| e66b690c93 | |||
| 242fd00e8a | |||
| c77a1faa69 | |||
| 540b609591 | |||
| ac5a409cdf | |||
| 4cbc751dad | |||
| 1dc579ce71 | |||
| 37282fffff | |||
| b3e98cb7eb | |||
| bd03d70937 | |||
| 716161e626 | |||
| 93a67847ba | |||
| 6873244e7e | |||
| c569a84f87 | |||
| 1e07927e78 | |||
| c4b8b85602 | |||
| 464e4d11e9 | |||
| 85e4a19f03 | |||
| 6263d01c73 | |||
| 967e646989 | |||
| e9d3b9dcde | |||
| 3065ba851e | |||
| 80522a2505 | |||
| 532e6c1c1d | |||
| 5cf314a314 | |||
| c08cfb9b73 | |||
| 61591633f8 | |||
| 9b5b58687d | |||
| fb7bec4be4 | |||
| 9dba03646b | |||
| ddd2ce07f3 | |||
| 3de5f5882c | |||
| 73e010434e | |||
| a9d6a5f618 | |||
| ef9cc4fceb | |||
| e104decf77 | |||
| 96e38da875 | |||
| ff95049f7c | |||
| 63cb4e70bc | |||
| e6ae9cae6b | |||
| 1f1e1401cf | |||
| af1159658d | |||
| 4e2b22135a | |||
| 4ee5a4c5c3 | |||
| aa14cfe18d | |||
| 0797c4ac97 | |||
| b4ea75f34f | |||
| e37a990820 | |||
| b54d68ebf1 | |||
| 4ae2126ded | |||
| c420670ebb | |||
| dae1f43359 | |||
| 38df5e8b07 | |||
| d1cd670af5 | |||
| 04e4b6c181 | |||
| 9559c5a025 | |||
| 42fa2e12db | |||
| f41583fd59 | |||
| b48704b3af | |||
| de3ebfecfe | |||
| 29311b1b5b | |||
| b131227b71 | |||
| ec45833cd8 | |||
| 4c2905b1f0 | |||
| 6e51be6c57 | |||
| b195168c83 | |||
| a722eca6aa | |||
| 1f6428ee1c | |||
| ab10fb466c | |||
| dcabf90409 | |||
| 27752f595c | |||
| c17598d4b4 | |||
| d74d9900da | |||
| 5505c9ab67 | |||
| 8d2ffea7df | |||
| 1233c939f8 | |||
| 46dd83c34e | |||
| 639aa85353 | |||
| 008b6f1db2 | |||
| f46ad4811e | |||
| b39b24e6b9 | |||
| 7f0133a4d6 | |||
| 85bc8bc8f0 | |||
| 32e1d4b2ef | |||
| f8d5af836f | |||
| 19ceb3f5b7 | |||
| f346c55cf1 | |||
| e797705dad | |||
| a331e14ef2 | |||
| d6b4c27302 | |||
| f8d7291923 | |||
| b59674ab77 | |||
| 0620b8b163 | |||
| f639d82693 | |||
| 13d2d41f0c | |||
| 015cd44136 | |||
| 4834f60a44 | |||
| 3327e1d8f2 | |||
| 40e002911c | |||
| 03bcc3b73f | |||
| f963df0658 | |||
| 0aa77d281f | |||
| 0988255693 | |||
| fb9e7cf5e1 | |||
| ecc1bd69b9 | |||
| 830f095a6e | |||
| 288f7e4e93 | |||
| a205ae12a4 | |||
| 1866426f11 | |||
| e4ab6c0c24 | |||
| 189c148761 | |||
| 8b7c1a195c | |||
| d77547aecf | |||
| 478a5c0e1a | |||
| 5c6757ecf6 | |||
| f2981cf12b | |||
| c3310a0772 | |||
| fe485acd4a | |||
| fbe19738cb | |||
| d29a62a335 | |||
| 6cc2013102 | |||
| 39ce7b75ca | |||
| f3959323ff | |||
| 0d62ab2ad4 | |||
| cbf9239d86 | |||
| 295875c45e | |||
| 5e363f7dd4 | |||
| 6bb0927f26 | |||
| 24bb679305 | |||
| ddc22b4d6b | |||
| 9a75131a98 | |||
| 26b4063435 | |||
| 8dd432c3a2 | |||
| 0e390f1a9b | |||
| 6fb83d66a2 | |||
| bf96688aef | |||
| eb4aeb47c1 | |||
| d906f3cf62 | |||
| 0defed9abe | |||
| ac925af3d0 | |||
| 4f08b2360c | |||
| fd60ce1198 | |||
| 00cdb13803 | |||
| ef6d747b37 | |||
| e26abb8684 | |||
| 82801242d3 | |||
| e53ed2319c | |||
| 8f512e5941 | |||
| 8a1b6b0684 | |||
| 5ac6caf257 | |||
| 36f460d32b | |||
| 802fcbafa0 | |||
| 1098b8cd9d | |||
| da8999f59a | |||
| bebc1f4d0d | |||
| 1212267da3 | |||
| d696ed8a5a | |||
| c3d17c5727 | |||
| cb25d0f2f3 | |||
| be535671bc | |||
| 63838f6e74 | |||
| 5ddf0dd789 | |||
| b003890dd2 | |||
| 8db8d4beba | |||
| d5309c7d94 | |||
| fb857ccf56 | |||
| 2668960bb9 | |||
| 8e4878fac0 | |||
| d4ef0f8aa8 | |||
| 752d89d177 | |||
| 0d7304eb8b | |||
| 48ff7cdbe8 | |||
| ca446ad7df | |||
| 5afcd8ddb3 | |||
| 5273408631 | |||
| 713c9fdd6f | |||
| 0a5c41ce23 | |||
| 48a916ab77 | |||
| 67ab602e3b | |||
| 801328ec42 | |||
| 4fe83467ee | |||
| dd34f07989 | |||
| 27a7a89990 | |||
| 5dafa3c5c9 | |||
| 6b242f47e4 | |||
| 446c7fb483 | |||
| 17c9c93456 | |||
| bbb2af7f53 | |||
| d65206c7fe | |||
| 954ffbfcaf | |||
| 327491c3a4 | |||
| 02eeb7f916 | |||
| e9ad43afbe | |||
| 434068a2ed | |||
| 7f5ea30904 | |||
| 53b6ccbac0 | |||
| 7e65d68392 | |||
| b3d35beeb9 | |||
| eaa0e9d1fa | |||
| fed7c2dc16 | |||
| 79951c3f17 | |||
| 221ffb446c | |||
| 0eb34cb979 | |||
| 79a4c83879 | |||
| 57f80290a1 | |||
| 4b2ede7a71 | |||
| 5e465fa417 | |||
| de5d66f5d2 | |||
| a50c8c6269 | |||
| cb56f89954 | |||
| 96379d0a62 | |||
| 68988524d6 | |||
| c278900581 | |||
| bbc9ed5778 | |||
| 1d0c156d2e | |||
| 7de5e2e7ef | |||
| 8d935b34eb | |||
| 9830959f11 | |||
| 8e790fdc47 | |||
| 0ef20c524f | |||
| 5ccaf2c23e | |||
| bec9511df1 | |||
| 017948c3bb | |||
| 1cb72e3e9c | |||
| e45f563b50 | |||
| 69d255f584 | |||
| dd08642a7c | |||
| 3ac0877418 | |||
| 37b39956b5 | |||
| 9a4fd81c70 | |||
| 0bb2e98af3 | |||
| 1c8d94c953 | |||
| 9573428201 | |||
| ca11efd3ee | |||
| 4a6a94a50e | |||
| 2d65b38155 | |||
| 587449ef97 | |||
| 06ffac9d7d | |||
| e32ed03f66 | |||
| a7543b407f | |||
| 98b1ba1e39 | |||
| e03ed7567a | |||
| 9f0581275b | |||
| 3f5c166417 | |||
| cf091377b6 | |||
| 0cc7a7014f | |||
| 4790ad53e3 | |||
| 62dc075834 | |||
| 41da04cd22 | |||
| 0c4fc56b80 | |||
| 907f0553d4 | |||
| 224f04db6c | |||
| f0bcf78941 | |||
| c08a4a2b0a | |||
| 8597984787 | |||
| 001ccf1ce9 | |||
| 082a974ee3 | |||
| 152c23b8f3 | |||
| b635822a85 | |||
| ec85e4b5b0 | |||
| 1acb7e0fe4 | |||
| 5914004a57 | |||
| c5afc66d46 | |||
| bc69660247 | |||
| 71c7c64fde | |||
| c284ac5287 | |||
| 639afe5b9b | |||
| 049b9c542b | |||
| 0118504cd3 | |||
| f4e69679ca | |||
| ce7a8ad808 | |||
| c17c011488 | |||
| 92762896ef | |||
| c699baf519 | |||
| 97b765b5cc | |||
| 40b41e646d | |||
| 63853db450 | |||
| 48dd3252cb | |||
| ee6f60e63c | |||
| f6abf90ba0 | |||
| 83ee0e0fb6 | |||
| 94f44d1b77 | |||
| e12c7473f8 | |||
| 407d69b370 | |||
| 774e795d97 | |||
| f698f74d3e | |||
| 80f9159f4d | |||
| 0ec25d55a0 | |||
| bb03e00279 | |||
| 4d3db2ab44 | |||
| c3d52af546 | |||
| 9672a13402 | |||
| 9564f7fdb8 | |||
| eba1f03363 | |||
| c7ca4d061f | |||
| 115f08ee49 | |||
| e33c680679 | |||
| 1e8ec783b4 | |||
| a6ed958687 | |||
| 4354f50168 | |||
| 8fc1227974 | |||
| d410f168bd | |||
| b38f9ad33c | |||
| f8311815ee | |||
| 3edb501973 | |||
| 49918d3302 | |||
| 876ab44a16 | |||
| 15296d2b1c | |||
| 1434522149 | |||
| 23af5fb06e | |||
| 6b8c1eb523 | |||
| 0984194ec6 | |||
| 26264e1d55 | |||
| dc5dedd5a3 | |||
| d49bfb562a | |||
| f90dd9d74d | |||
| 8d24c0af0d | |||
| 174a01cb6b | |||
| 360e0ff534 | |||
| 4f2721e93f | |||
| 0dce3b8b8c | |||
| 5042c2b30a | |||
| b45cf6124f | |||
| c8f280ac90 | |||
| 7eb936883a | |||
| c3b5a92a48 | |||
| eb054897d6 | |||
| f6dbda4056 | |||
| 5992d2a1d2 | |||
| a53976967a | |||
| 1be7508340 | |||
| af135fa42c | |||
| 7aa5195e87 | |||
| 04c3481734 | |||
| 582b462326 | |||
| b233715796 | |||
| b93fc80011 | |||
| 41a6b34768 | |||
| 17a6a871ae | |||
| 5fceef1dc3 | |||
| 9b04d2e51c | |||
| 51b426f0b4 | |||
| 021c4f2598 | |||
| ac96b8d4ae | |||
| bc8719e336 | |||
| bd38d64e66 | |||
| 74b5d6d12b | |||
| ddd11939a5 | |||
| 3caa5f2042 | |||
| 5226d507d4 | |||
| 274b659905 | |||
| a0b9714d72 | |||
| 36aea52ae0 | |||
| e0643cd744 | |||
| 27fab0f573 | |||
| 183a4d49d8 | |||
| edacc4eb54 | |||
| 1e7d7a147b | |||
| 8ee549efbf | |||
| 699476da90 | |||
| d763feb803 | |||
| d3bfa75251 | |||
| 833af55806 | |||
| d1246c65bd | |||
| 38db890660 | |||
| 01c18f6303 | |||
| c5e2aed164 | |||
| 4d1d2fedb7 | |||
| ab6363a124 | |||
| a0e7dcf4ff | |||
| da33f1815a | |||
| f089d1f0a4 | |||
| 72f58b0405 | |||
| 4bd6c2171c | |||
| 67494c1b0b | |||
| 3264149a2c | |||
| 8417fcb604 | |||
| 331fbb66bd | |||
| 400833f834 | |||
| a7e6b8ea3f | |||
| 6e31d0f2c3 | |||
| b9a660683c | |||
| 014350a26b | |||
| 06a0ac895d | |||
| 34a47e9e44 | |||
| f5a9e4bafa | |||
| 66339481cf | |||
| 2e97b56deb | |||
| 8adb62fd3a | |||
| 43537d414b | |||
| f2fab57187 | |||
| 10a7ae8d47 | |||
| 03c90d7b60 | |||
| b85b4b1e1b | |||
| 1d0d14876c | |||
| b71a90a3c5 | |||
| 92f33c08f7 | |||
| 53de97db4e | |||
| 5574c5fa49 | |||
| 7373e2019c | |||
| 4bb19152c4 | |||
| dc0b8c7572 | |||
| b8265d54bb | |||
| 0e3efdfe87 | |||
| 363ec841d1 | |||
| f8d0ddb3f7 | |||
| 4aa5961860 | |||
| 7862b74e99 | |||
| c5710b858e | |||
| 8873137ed0 | |||
| 37d792352d | |||
| 52e4414bc5 | |||
| f96b7c5056 | |||
| 4daa8e7c63 | |||
| 41f25341fd | |||
| de77eda33d | |||
| ee58fcc898 | |||
| ae3cb7b37b | |||
| 5f83cb6a14 | |||
| ae24b73b32 | |||
| 4aedbb52fa | |||
| 20dab4d89d | |||
| e871481042 | |||
| d727b03d95 | |||
| 0cc3031864 | |||
| 59e6874a4a | |||
| 930ef3fd11 | |||
| 35f8a71c71 | |||
| 86762c5e90 | |||
| 3c75fc2ced | |||
| 702edf7908 | |||
| 54b4db86d2 | |||
| 0eadab49f1 | |||
| 45e98e0282 | |||
| b97c54a54b | |||
| e22296fd79 | |||
| 6c17d7d732 | |||
| 0d58ac61bc | |||
| 7c08fbe144 | |||
| 7777147af5 | |||
| 2042733dc0 | |||
| d4cf392387 | |||
| c881727747 | |||
| ee00699cb3 | |||
| b45749af16 | |||
| 54dec8d30d | |||
| 6f3fb47e4a | |||
| 7238238d1f | |||
| 84f6638f50 | |||
| e390a95bd3 | |||
| 3616c92148 | |||
| 2fcc7e1188 | |||
| 8a06f4ad82 | |||
| 853e14f369 | |||
| c1aa33862d | |||
| 30dc5fa0cf | |||
| 94e168fa15 | |||
| 4217d7402b | |||
| 3d28a9090c | |||
| 271de1eceb | |||
| b6aae1f8a9 | |||
| c313a78c3c | |||
| 37d65dac3d | |||
| 5ebf013d4e | |||
| 02c22c9efb | |||
| d953519db6 | |||
| dd97e4ea82 | |||
| a20e03fce9 | |||
| 5306e1cd15 | |||
| e974c96eda | |||
| 2004e58b53 | |||
| eb2d7b1f4f | |||
| 47763d1e1a | |||
| 44447b85c9 | |||
| b813dcd9d0 | |||
| 3964296ae6 | |||
| da9a61c28a | |||
| 6e16f589bd | |||
| 6b70443515 | |||
| c9854d43a5 | |||
| 04708ae2b2 | |||
| bbb9babf27 | |||
| e5daf35f65 | |||
| 87c72953b2 | |||
| 89e2d03a81 | |||
| fa5651f335 | |||
| 443447a068 | |||
| b33c0fc4dd | |||
| 8e0b718a4a | |||
| b51c505d9e | |||
| 8bba11e1bb | |||
| 4b54e980e2 | |||
| 033a56fe6d | |||
| 3682d9fa6c | |||
| ce987b4f6d | |||
| 74efd850af | |||
| df8b1c0240 | |||
| d65c0c8bea | |||
| 2d5631284b | |||
| 3952fc10a6 | |||
| 0881301b6d | |||
| 530ea474d1 | |||
| 219540281f | |||
| b74115b604 | |||
| 1630392953 | |||
| 861ef6312e | |||
| f64aa4dfd4 | |||
| 786c41ad79 | |||
| b24d80680e | |||
| 1a1f417633 | |||
| bbfee27fd3 | |||
| 691e81d827 | |||
| 0ac1dd314a | |||
| 82f4cc799b | |||
| 4d8d069bbc | |||
| 5a396cc997 | |||
| 0883321d9e | |||
| 2768f19b7c | |||
| 20bd83232e | |||
| d72970b5b6 | |||
| 9c1bea00ad | |||
| 8d8bf73c1b | |||
| e5fb888d67 | |||
| 82df7a66ec | |||
| 0202a97e97 | |||
| b34886ead6 | |||
| 6f6341bc09 | |||
| 5f8e91455f | |||
| a5099b5163 | |||
| 27103124bf | |||
| f2d34b2c03 | |||
| 25cba65c6e | |||
| a756d2b765 | |||
| 740d46a50e | |||
| d8d92a6d2c | |||
| 137193ab12 | |||
| fcef60445c | |||
| 9e0897b2cb | |||
| a23a3b95d6 | |||
| 1ac0be50a7 | |||
| 618bbc4bda | |||
| 8c434c7862 | |||
| 7f153b32e4 | |||
| 4fc8e8dd61 | |||
| 48e5ee2310 | |||
| 92e3a1e69e | |||
| 7f0e3e288e | |||
| dc27e67b19 | |||
| 4c62e8ade9 | |||
| 87853921c3 | |||
| 8a496ccebc | |||
| 3e5f804791 | |||
| 62f8353bd7 | |||
| 1dd9273f70 | |||
| 2eeaef00e1 | |||
| 5c0c60a5b9 | |||
| 6fcbb108c6 | |||
| 71761a48ad | |||
| 495d74f7c9 | |||
| fda77179a3 | |||
| 578495bab6 | |||
| 9a5c8c4ce6 | |||
| 0504c09a9a | |||
| 9d062f9849 | |||
| 0527201ae5 | |||
| cf5c78029c | |||
| 26cc4497eb | |||
| c35179b098 | |||
| b2d0cbb264 | |||
| ebf760a477 | |||
| 9fcb1a2d0e | |||
| 27bb938d9e | |||
| 75bd056bbe | |||
| ad202be374 | |||
| ca35b66597 | |||
| e9e68171bb | |||
| e791ebbe76 | |||
| d92893b2c7 | |||
| c68a2a36fa | |||
| 89c47c1879 | |||
| b9cda88363 | |||
| 52028ddef2 | |||
| c3845f4393 | |||
| c9157dc55d | |||
| c3b53b28e3 | |||
| e636d7b9d5 | |||
| bd86c5430c | |||
| 4a0bb31866 | |||
| b7f6c7df06 | |||
| 327d27591f | |||
| 5041c07c7e | |||
| 505d601488 | |||
| bca7f208a6 | |||
| 4f031149e8 | |||
| b7011d853a | |||
| 06186c9b12 | |||
| 7a5faa9619 | |||
| e5792fd415 | |||
| 45dbc02868 | |||
| f1cc2c8d8b | |||
| 734af87f2f | |||
| 78d589fe78 | |||
| c9fcc906fb | |||
| f9fc2a44cd |
@@ -3235,6 +3235,42 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sgross-emlix",
|
||||
"name": "Sebastian Groß",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/143394709?v=4",
|
||||
"profile": "https://github.com/sgross-emlix",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AnouarTouati",
|
||||
"name": "Anouar Touati",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/41107778?v=4",
|
||||
"profile": "https://github.com/AnouarTouati",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "aHVzY2g",
|
||||
"name": "aHVzY2g",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/25596663?v=4",
|
||||
"profile": "https://github.com/aHVzY2g",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "brlin-tw",
|
||||
"name": "林博仁 Buo-ren Lin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13408130?v=4",
|
||||
"profile": "https://brlin.me",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ MYSQL_ROOT_PASSWORD=changeme1234
|
||||
# REQUIRED: BASIC APP SETTINGS
|
||||
# --------------------------------------------
|
||||
APP_ENV=develop
|
||||
APP_DEBUG=false
|
||||
APP_DEBUG=true
|
||||
# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here
|
||||
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||
APP_URL=http://localhost:8000
|
||||
@@ -158,7 +158,7 @@ RESET_PASSWORD_LINK_EXPIRES=900
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: MISC
|
||||
# --------------------------------------------
|
||||
LOG_CHANNEL=stderr
|
||||
LOG_CHANNEL=single
|
||||
LOG_MAX_DAYS=10
|
||||
APP_LOCKED=false
|
||||
APP_CIPHER=AES-256-CBC
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# --------------------------------------------
|
||||
# REQUIRED: DOCKER SPECIFIC SETTINGS
|
||||
# --------------------------------------------
|
||||
APP_VERSION=v6.4.1
|
||||
APP_VERSION=
|
||||
APP_PORT=8000
|
||||
|
||||
# --------------------------------------------
|
||||
@@ -9,7 +9,7 @@ APP_PORT=8000
|
||||
# --------------------------------------------
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
# Please regenerate the APP_KEY value by calling `docker compose run --rm snipeit php artisan key:generate --show`. Copy paste the value here
|
||||
# Please regenerate the APP_KEY value by calling `docker compose run --rm app php artisan key:generate --show`. Copy paste the value here
|
||||
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||
APP_URL=http://localhost:8000
|
||||
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
||||
|
||||
@@ -80,6 +80,12 @@ MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||
BACKUP_ENV=true
|
||||
ALLOW_BACKUP_DELETE=false
|
||||
ALLOW_DATA_PURGE=false
|
||||
ALL_BACKUP_KEEP_DAYS=7
|
||||
DAILY_BACKUP_KEEP_DAYS=16
|
||||
WEEKLY_BACKUP_KEEP_WEEKS=8
|
||||
MONTHLY_BACKUP_KEEP_MONTHS=4
|
||||
YEARLY_BACKUP_KEEP_YEARS=2
|
||||
BACKUP_PURGE_OLDEST_AT_MEGS=5000
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SESSION SETTINGS
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars.githubusercontent.com/u/47315739?v=4" width="110px;"/><br /><sub>bilias</sub>](https://github.com/bilias)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ RUN mkdir -p /var/www/.composer && chown apache /var/www/.composer
|
||||
|
||||
# Install dependencies
|
||||
USER apache
|
||||
RUN COMPOSER_CACHE_DIR=/dev/null composer install --no-dev --working-dir=/var/www/html
|
||||
RUN COMPOSER_CACHE_DIR=/dev/null composer install --working-dir=/var/www/html
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -427,7 +427,13 @@ class LdapSync extends Command
|
||||
$user->groups()->attach($ldap_default_group);
|
||||
}
|
||||
//updates assets location based on user's location
|
||||
Asset::where('assigned_to', '=', $user->id)->where('assigned_type', '=', User::class)->update(['location_id' => $user->location_id]);
|
||||
if ($user->wasChanged('location_id')) {
|
||||
foreach ($user->assets as $asset) {
|
||||
$asset->location_id = $user->location_id;
|
||||
// TODO: somehow add note? "Asset Location Changed because of thing"
|
||||
$asset->save();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
foreach ($user->getErrors()->getMessages() as $key => $err) {
|
||||
|
||||
@@ -59,7 +59,7 @@ class ObjectImportCommand extends Command
|
||||
$classString = "App\\Importer\\{$class}Importer";
|
||||
$importer = new $classString($filename);
|
||||
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
|
||||
->setUserId($this->option('user_id'))
|
||||
->setCreatedBy($this->option('user_id'))
|
||||
->setUpdating($this->option('update'))
|
||||
->setShouldNotify($this->option('send-welcome'))
|
||||
->setUsernameFormat($this->option('username_format'));
|
||||
|
||||
@@ -50,12 +50,12 @@ class ResetDemoSettings extends Command
|
||||
$settings->alert_email = 'service@snipe-it.io';
|
||||
$settings->login_note = 'Use `admin` / `password` to login to the demo.';
|
||||
$settings->header_color = null;
|
||||
$settings->barcode_type = 'QRCODE';
|
||||
$settings->label2_2d_type = 'QRCODE';
|
||||
$settings->default_currency = 'USD';
|
||||
$settings->brand = 2;
|
||||
$settings->ldap_enabled = 0;
|
||||
$settings->full_multiple_companies_support = 0;
|
||||
$settings->alt_barcode = 'C128';
|
||||
$settings->label2_1d_type = 'C128';
|
||||
$settings->skin = '';
|
||||
$settings->email_domain = 'snipeitapp.com';
|
||||
$settings->email_format = 'filastname';
|
||||
@@ -65,7 +65,7 @@ class ResetDemoSettings extends Command
|
||||
$settings->thumbnail_max_h = '30';
|
||||
$settings->locale = 'en-US';
|
||||
$settings->version_footer = 'on';
|
||||
$settings->support_footer = null;
|
||||
$settings->support_footer = 'on';
|
||||
$settings->saml_enabled = '0';
|
||||
$settings->saml_sp_x509cert = null;
|
||||
$settings->saml_idp_metadata = null;
|
||||
|
||||
@@ -51,6 +51,8 @@ class SQLStreamer {
|
||||
/* we *could* have made the ^INSERT INTO blah VALUES$ turn on the capturing state, and closed it with
|
||||
a ^(blahblah);$ but it's cleaner to not have to manage the state machine. We're just going to
|
||||
assume that (blahblah), or (blahblah); are values for INSERT and are always acceptable. */
|
||||
"<^/\*!40101 SET NAMES '?[a-zA-Z0-9_-]+'? \*/;$>" => false, //using weird delimiters (<,>) for readability. allow quoted or unquoted charsets
|
||||
"<^/\*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' \*/;$>" => false, //same, now handle zero-values
|
||||
];
|
||||
|
||||
foreach($allowed_statements as $statement => $statechange) {
|
||||
@@ -370,7 +372,7 @@ class RestoreFromBackup extends Command
|
||||
if ($this->option('sanitize-guess-prefix')) {
|
||||
$prefix = SQLStreamer::guess_prefix($sql_contents);
|
||||
$this->line($prefix);
|
||||
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
||||
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitize your SQL.");
|
||||
}
|
||||
|
||||
// If we're doing --sql-stdout-only, handle that now so we don't have to open pipes to mysql and all of that silliness
|
||||
|
||||
@@ -72,7 +72,7 @@ class SendAcceptanceReminder extends Command
|
||||
$locale = $acceptance->assignedTo?->locale;
|
||||
$email = $acceptance->assignedTo?->email;
|
||||
if(!$email){
|
||||
$this->info($acceptance->assignedTo->present()->fullName().' has no email address.');
|
||||
$this->info($acceptance->assignedTo?->present()->fullName().' has no email address.');
|
||||
}
|
||||
$item_count = $unacceptedAssetGroup->count();
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Mail\ExpiringAssetsMail;
|
||||
use App\Mail\ExpiringLicenseMail;
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\Recipients\AlertRecipient;
|
||||
use App\Models\Setting;
|
||||
use App\Notifications\ExpiringAssetsNotification;
|
||||
use App\Notifications\ExpiringLicenseNotification;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendExpirationAlerts extends Command
|
||||
{
|
||||
@@ -47,22 +47,22 @@ class SendExpirationAlerts extends Command
|
||||
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {
|
||||
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
||||
return new AlertRecipient($item);
|
||||
});
|
||||
|
||||
$recipients = collect(explode(',', $settings->alert_email))
|
||||
->map(fn($item) => trim($item)) // Trim each email
|
||||
->all();
|
||||
// Expiring Assets
|
||||
$assets = Asset::getExpiringWarrantee($threshold);
|
||||
|
||||
if ($assets->count() > 0) {
|
||||
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
|
||||
\Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));
|
||||
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $threshold));
|
||||
}
|
||||
|
||||
// Expiring licenses
|
||||
$licenses = License::getExpiringLicenses($threshold);
|
||||
if ($licenses->count() > 0) {
|
||||
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold]));
|
||||
\Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold));
|
||||
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $threshold));
|
||||
}
|
||||
} else {
|
||||
if ($settings->alert_email == '') {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NoteAdded
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
public $itemNoteAddedOn;
|
||||
public $note;
|
||||
public $noteAddedBy;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($itemNoteAddedOn, User $noteAddedBy, $note)
|
||||
{
|
||||
$this->itemNoteAddedOn = $itemNoteAddedOn;
|
||||
$this->note = $note;
|
||||
$this->noteAddedBy = $noteAddedBy;
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,9 @@ class IconHelper
|
||||
return 'fa-regular fa-id-card';
|
||||
case 'department' :
|
||||
return 'fa-solid fa-building-user';
|
||||
|
||||
case 'note':
|
||||
case 'notes':
|
||||
return 'fas fa-sticky-note';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class AccessoriesController extends Controller
|
||||
public function index() : View
|
||||
{
|
||||
$this->authorize('index', Accessory::class);
|
||||
return view('accessories/index');
|
||||
return view('accessories.index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +100,7 @@ class AccessoriesController extends Controller
|
||||
|
||||
if ($item = Accessory::find($accessoryId)) {
|
||||
$this->authorize($item);
|
||||
return view('accessories/edit', compact('item'))->with('category_type', 'accessory');
|
||||
return view('accessories.edit', compact('item'))->with('category_type', 'accessory');
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
@@ -236,7 +236,7 @@ class AccessoriesController extends Controller
|
||||
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryID);
|
||||
$this->authorize('view', $accessory);
|
||||
if (isset($accessory->id)) {
|
||||
return view('accessories/view', compact('accessory'));
|
||||
return view('accessories.view', compact('accessory'));
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist', ['id' => $accessoryID]));
|
||||
|
||||
@@ -51,15 +51,15 @@ class AccessoriesFilesController extends Controller
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('general.file_upload_success'));
|
||||
return redirect()->route('accessories.show', $accessory->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->with('error', trans('general.no_files_uploaded'));
|
||||
return redirect()->route('accessories.show', $accessory->id)->withFragment('files')->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('accessories.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,30 +72,27 @@ class AccessoriesFilesController extends Controller
|
||||
*/
|
||||
public function destroy($accessoryId = null, $fileId = null) : RedirectResponse
|
||||
{
|
||||
$accessory = Accessory::find($accessoryId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($accessory->id)) {
|
||||
if ($accessory = Accessory::find($accessoryId)) {
|
||||
$this->authorize('update', $accessory);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('accessories/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('accessories/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
|
||||
if (Storage::exists('private_uploads/accessories/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('private_uploads/accessories/' . $log->filename);
|
||||
$log->delete();
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +122,11 @@ class AccessoriesFilesController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.log_record_not_found'));
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_not_found'));
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,20 +75,23 @@ class AccessoryCheckoutController extends Controller
|
||||
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||
|
||||
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||
AccessoryCheckout::create([
|
||||
|
||||
$accessory_checkout = new AccessoryCheckout([
|
||||
'accessory_id' => $accessory->id,
|
||||
'created_at' => Carbon::now(),
|
||||
'created_by' => auth()->id(),
|
||||
'assigned_to' => $target->id,
|
||||
'assigned_type' => $target::class,
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
$accessory_checkout->created_by = auth()->id();
|
||||
$accessory_checkout->save();
|
||||
}
|
||||
|
||||
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
||||
|
||||
// Set this as user since we only allow checkout to user for this item type
|
||||
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
|
||||
$request->request->add(['assigned_user' => $target->id]);
|
||||
$request->request->add(['assigned_to' => $target->id]);
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||
|
||||
|
||||
@@ -40,10 +40,13 @@ class ActionlogController extends Controller
|
||||
public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse
|
||||
{
|
||||
$this->authorize('view', \App\Models\Asset::class);
|
||||
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
||||
|
||||
if (config('filesystems.default') == 's3_private') {
|
||||
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/'.$filename, now()->addMinutes(5)));
|
||||
}
|
||||
|
||||
if (Storage::exists('private_uploads/eula-pdfs/'.$filename)) {
|
||||
return response()->download($file);
|
||||
return response()->download(config('app.private_uploads').'/eula-pdfs/'.$filename);
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
|
||||
|
||||
@@ -13,6 +13,7 @@ use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -184,39 +185,33 @@ class AccessoriesController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
* Get the list of checkouts for a specific accessory
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v4.0]
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return | array
|
||||
*/
|
||||
public function checkedout($id, Request $request)
|
||||
public function checkedout(Request $request, $id)
|
||||
{
|
||||
$this->authorize('view', Accessory::class);
|
||||
|
||||
$accessory = Accessory::with('lastCheckout')->findOrFail($id);
|
||||
|
||||
$offset = request('offset', 0);
|
||||
$limit = request('limit', 50);
|
||||
|
||||
$accessory_checkouts = $accessory->checkouts;
|
||||
$total = $accessory_checkouts->count();
|
||||
|
||||
if ($total < $offset) {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
$accessory_checkouts = $accessory->checkouts()->skip($offset)->take($limit)->get();
|
||||
// Total count of all checkouts for this asset
|
||||
$accessory_checkouts = $accessory->checkouts();
|
||||
|
||||
// Check for search text in the request
|
||||
if ($request->filled('search')) {
|
||||
|
||||
$accessory_checkouts = $accessory->checkouts()->TextSearch($request->input('search'))
|
||||
->get();
|
||||
$total = $accessory_checkouts->count();
|
||||
$accessory_checkouts = $accessory_checkouts->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_checkouts, $total);
|
||||
$total = $accessory_checkouts->count();
|
||||
$accessory_checkouts = $accessory_checkouts->skip($offset)->take($limit)->get();
|
||||
|
||||
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory_checkouts, $total);
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +222,7 @@ class AccessoriesController extends Controller
|
||||
* @since [v4.0]
|
||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, $id)
|
||||
{
|
||||
@@ -249,7 +244,7 @@ class AccessoriesController extends Controller
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v4.0]
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
@@ -284,14 +279,17 @@ class AccessoriesController extends Controller
|
||||
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||
|
||||
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||
AccessoryCheckout::create([
|
||||
|
||||
$accessory_checkout = new AccessoryCheckout([
|
||||
'accessory_id' => $accessory->id,
|
||||
'created_at' => Carbon::now(),
|
||||
'created_by' => auth()->id(),
|
||||
'assigned_to' => $target->id,
|
||||
'assigned_type' => $target::class,
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
$accessory_checkout->created_by = auth()->id();
|
||||
$accessory_checkout->save();
|
||||
}
|
||||
|
||||
// Set this value to be able to pass the qty through to the event
|
||||
|
||||
@@ -122,7 +122,7 @@ class AssetMaintenancesController extends Controller
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function store(Request $request) : JsonResponse
|
||||
public function store(Request $request) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
// create a new model instance
|
||||
@@ -149,7 +149,7 @@ class AssetMaintenancesController extends Controller
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function update(Request $request, $id) : JsonResponse
|
||||
public function update(Request $request, $id) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
@@ -186,7 +186,7 @@ class AssetMaintenancesController extends Controller
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function destroy($assetMaintenanceId) : JsonResponse
|
||||
public function destroy($assetMaintenanceId) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
@@ -208,7 +208,7 @@ class AssetMaintenancesController extends Controller
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function show($assetMaintenanceId) : JsonResponse
|
||||
public function show($assetMaintenanceId) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Actionlog;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Http\Transformers\AssetModelsTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
@@ -68,37 +69,15 @@ class AssetModelFilesController extends Controller
|
||||
/**
|
||||
* List the files for an asset.
|
||||
*
|
||||
* @param int $assetModelId
|
||||
* @param int $assetmodel
|
||||
* @since [v7.0.12]
|
||||
* @author [r-xyz]
|
||||
*/
|
||||
public function list($assetModelId = null) : JsonResponse
|
||||
public function list($assetmodel_id) : JsonResponse | array
|
||||
{
|
||||
// Start by checking if the asset being acted upon exists
|
||||
if (! $assetModel = AssetModel::find($assetModelId)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
|
||||
}
|
||||
|
||||
// the asset is valid
|
||||
if (isset($assetModel->id)) {
|
||||
$this->authorize('view', $assetModel);
|
||||
|
||||
// Check that there are some uploads on this asset that can be listed
|
||||
if ($assetModel->uploads->count() > 0) {
|
||||
$files = array();
|
||||
foreach ($assetModel->uploads as $upload) {
|
||||
array_push($files, $upload);
|
||||
}
|
||||
// Give the list of files back to the user
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $files, trans('admin/models/message.upload.success')));
|
||||
}
|
||||
|
||||
// There are no files.
|
||||
return response()->json(Helper::formatStandardApiResponse('success', array(), trans('admin/models/message.upload.success')));
|
||||
}
|
||||
|
||||
// Send back an error message
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.error')), 500);
|
||||
$assetmodel = AssetModel::with('uploads')->find($assetmodel_id);
|
||||
$this->authorize('view', $assetmodel);
|
||||
return (new AssetModelsTransformer)->transformAssetModelFiles($assetmodel, $assetmodel->uploads()->count());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn;
|
||||
use App\Http\Requests\StoreAssetRequest;
|
||||
use App\Http\Requests\UpdateAssetRequest;
|
||||
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
@@ -26,11 +27,9 @@ use App\Models\License;
|
||||
use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\View\Label;
|
||||
@@ -129,6 +128,7 @@ class AssetsController extends Controller
|
||||
|
||||
$assets = Asset::select('assets.*')
|
||||
->with(
|
||||
'model',
|
||||
'location',
|
||||
'assetstatus',
|
||||
'company',
|
||||
@@ -140,7 +140,7 @@ class AssetsController extends Controller
|
||||
'model.manufacturer',
|
||||
'model.fieldset',
|
||||
'supplier'
|
||||
); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
); // it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
|
||||
|
||||
if ($filter_non_deprecable_assets) {
|
||||
@@ -765,9 +765,13 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
if ($problems_updating_encrypted_custom_fields) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.encrypted_warning')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
|
||||
// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.encrypted_warning')));
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
|
||||
/// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
|
||||
}
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
@@ -1214,6 +1218,27 @@ class AssetsController extends Controller
|
||||
return (new AssetsTransformer)->transformRequestedAssets($assets, $total);
|
||||
}
|
||||
|
||||
|
||||
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
|
||||
{
|
||||
|
||||
return [];
|
||||
// to do
|
||||
}
|
||||
|
||||
public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$this->authorize('view', $asset);
|
||||
$accessory_checkouts = AccessoryCheckout::AssetsAssigned()->with('adminuser')->with('accessories');
|
||||
|
||||
$offset = ($request->input('offset') > $accessory_checkouts->count()) ? $accessory_checkouts->count() : app('api_offset_value');
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$total = $accessory_checkouts->count();
|
||||
$accessory_checkouts = $accessory_checkouts->skip($offset)->take($limit)->get();
|
||||
return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total);
|
||||
}
|
||||
/**
|
||||
* Generate asset labels by tag
|
||||
*
|
||||
|
||||
@@ -39,6 +39,7 @@ class CategoriesController extends Controller
|
||||
'components_count',
|
||||
'licenses_count',
|
||||
'image',
|
||||
'notes',
|
||||
];
|
||||
|
||||
$categories = Category::select([
|
||||
@@ -52,6 +53,7 @@ class CategoriesController extends Controller
|
||||
'require_acceptance',
|
||||
'checkin_email',
|
||||
'image',
|
||||
'notes',
|
||||
])
|
||||
->with('adminuser')
|
||||
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
|
||||
|
||||
@@ -38,11 +38,12 @@ class CompaniesController extends Controller
|
||||
'accessories_count',
|
||||
'consumables_count',
|
||||
'components_count',
|
||||
'notes',
|
||||
];
|
||||
|
||||
$companies = Company::withCount(['assets as assets_count' => function ($query) {
|
||||
$query->AssetsForShow();
|
||||
}])->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
||||
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$companies->TextSearch($request->input('search'));
|
||||
|
||||
@@ -23,7 +23,7 @@ class DepartmentsController extends Controller
|
||||
public function index(Request $request) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Department::class);
|
||||
$allowed_columns = ['id', 'name', 'image', 'users_count'];
|
||||
$allowed_columns = ['id', 'name', 'image', 'users_count', 'notes'];
|
||||
|
||||
$departments = Department::select(
|
||||
'departments.id',
|
||||
@@ -35,7 +35,8 @@ class DepartmentsController extends Controller
|
||||
'departments.manager_id',
|
||||
'departments.created_at',
|
||||
'departments.updated_at',
|
||||
'departments.image'
|
||||
'departments.image',
|
||||
'departments.notes',
|
||||
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
@@ -72,6 +73,9 @@ class DepartmentsController extends Controller
|
||||
case 'manager':
|
||||
$departments->OrderManager($order);
|
||||
break;
|
||||
case 'company':
|
||||
$departments->OrderCompany($order);
|
||||
break;
|
||||
default:
|
||||
$departments->orderBy($sort, $order);
|
||||
break;
|
||||
|
||||
@@ -24,7 +24,7 @@ class GroupsController extends Controller
|
||||
|
||||
$this->authorize('view', Group::class);
|
||||
|
||||
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
|
||||
$groups = Group::select('id', 'name', 'permissions', 'notes', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$groups = $groups->TextSearch($request->input('search'));
|
||||
@@ -81,6 +81,7 @@ class GroupsController extends Controller
|
||||
|
||||
$group->name = $request->input('name');
|
||||
$group->created_by = auth()->id();
|
||||
$group->notes = $request->input('notes');
|
||||
$group->permissions = json_encode($request->input('permissions', $groupPermissions));
|
||||
|
||||
if ($group->save()) {
|
||||
@@ -118,6 +119,7 @@ class GroupsController extends Controller
|
||||
$group = Group::findOrFail($id);
|
||||
|
||||
$group->name = $request->input('name');
|
||||
$group->notes = $request->input('notes');
|
||||
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
||||
|
||||
if ($group->save()) {
|
||||
|
||||
@@ -9,12 +9,14 @@ use App\Http\Transformers\ImportsTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\Import;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Csv\Reader;
|
||||
use Onnov\DetectEncoding\EncodingDetector;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -45,6 +47,8 @@ class ImportController extends Controller
|
||||
$path = config('app.private_uploads').'/imports';
|
||||
$results = [];
|
||||
$import = new Import;
|
||||
$detector = new EncodingDetector();
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (! in_array($file->getMimeType(), [
|
||||
'application/vnd.ms-excel',
|
||||
@@ -55,7 +59,6 @@ class ImportController extends Controller
|
||||
'text/comma-separated-values',
|
||||
'text/tsv', ])) {
|
||||
$results['error'] = 'File type must be CSV. Uploaded file is '.$file->getMimeType();
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 422);
|
||||
}
|
||||
|
||||
@@ -63,7 +66,25 @@ class ImportController extends Controller
|
||||
if (! ini_get('auto_detect_line_endings')) {
|
||||
ini_set('auto_detect_line_endings', '1');
|
||||
}
|
||||
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
|
||||
$encoding = $detector->getEncoding($file_contents);
|
||||
$reader = null;
|
||||
if (strcasecmp($encoding, 'UTF-8') != 0) {
|
||||
$transliterated = iconv($encoding, 'UTF-8', $file_contents);
|
||||
if ($transliterated !== false) {
|
||||
$tmpname = tempnam(sys_get_temp_dir(), '');
|
||||
$tmpresults = file_put_contents($tmpname, $transliterated);
|
||||
if ($tmpresults !== false) {
|
||||
$transliterated = null; //save on memory?
|
||||
$newfile = new UploadedFile($tmpname, $file->getClientOriginalName(), null, null, true); //WARNING: this is enabling 'test mode' - which is gross, but otherwise the file won't be treated as 'uploaded'
|
||||
if ($newfile->isValid()) {
|
||||
$file = $newfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
|
||||
$file_contents = null; //try to save on memory, I guess?
|
||||
|
||||
try {
|
||||
$import->header_row = $reader->fetchOne(0);
|
||||
|
||||
@@ -3,17 +3,20 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Transformers\AccessoriesTransformer;
|
||||
use App\Http\Transformers\AssetsTransformer;
|
||||
use App\Http\Transformers\LocationsTransformer;
|
||||
use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Location;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class LocationsController extends Controller
|
||||
{
|
||||
@@ -28,26 +31,29 @@ class LocationsController extends Controller
|
||||
{
|
||||
$this->authorize('view', Location::class);
|
||||
$allowed_columns = [
|
||||
'id',
|
||||
'name',
|
||||
'accessories_count',
|
||||
'address',
|
||||
'address2',
|
||||
'assets_count',
|
||||
'assets_count',
|
||||
'assigned_accessories_count',
|
||||
'assigned_assets_count',
|
||||
'assigned_assets_count',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'zip',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'manager_id',
|
||||
'image',
|
||||
'assigned_assets_count',
|
||||
'users_count',
|
||||
'assets_count',
|
||||
'assigned_assets_count',
|
||||
'assets_count',
|
||||
'rtd_assets_count',
|
||||
'currency',
|
||||
'id',
|
||||
'image',
|
||||
'ldap_ou',
|
||||
'manager_id',
|
||||
'name',
|
||||
'rtd_assets_count',
|
||||
'state',
|
||||
'updated_at',
|
||||
'users_count',
|
||||
'zip',
|
||||
'notes',
|
||||
];
|
||||
|
||||
$locations = Location::with('parent', 'manager', 'children')->select([
|
||||
@@ -68,8 +74,12 @@ class LocationsController extends Controller
|
||||
'locations.image',
|
||||
'locations.ldap_ou',
|
||||
'locations.currency',
|
||||
])->withCount('assignedAssets as assigned_assets_count')
|
||||
'locations.notes',
|
||||
])
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('assignedAccessories as assigned_accessories_count')
|
||||
->withCount('accessories as accessories_count')
|
||||
->withCount('rtd_assets as rtd_assets_count')
|
||||
->withCount('children as children_count')
|
||||
->withCount('users as users_count');
|
||||
@@ -182,6 +192,7 @@ class LocationsController extends Controller
|
||||
'locations.updated_at',
|
||||
'locations.image',
|
||||
'locations.currency',
|
||||
'locations.notes',
|
||||
])
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
@@ -224,7 +235,17 @@ class LocationsController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
|
||||
}
|
||||
|
||||
|
||||
public function assets(Request $request, Location $location) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$this->authorize('view', $location);
|
||||
$assets = Asset::where('location_id', '=', $location->id)->with('model', 'model.category', 'assetstatus', 'location', 'company', 'defaultLoc');
|
||||
$assets = $assets->get();
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||
}
|
||||
|
||||
public function assignedAssets(Request $request, Location $location) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$this->authorize('view', $location);
|
||||
@@ -233,6 +254,20 @@ class LocationsController extends Controller
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||
}
|
||||
|
||||
public function assignedAccessories(Request $request, Location $location) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Accessory::class);
|
||||
$this->authorize('view', $location);
|
||||
$accessory_checkouts = AccessoryCheckout::LocationAssigned()->where('assigned_to', $location->id)->with('adminuser')->with('accessories');
|
||||
|
||||
$offset = ($request->input('offset') > $accessory_checkouts->count()) ? $accessory_checkouts->count() : app('api_offset_value');
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$total = $accessory_checkouts->count();
|
||||
$accessory_checkouts = $accessory_checkouts->skip($offset)->take($limit)->get();
|
||||
return (new LocationsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
|
||||
@@ -39,7 +39,8 @@ class ManufacturersController extends Controller
|
||||
'assets_count',
|
||||
'consumables_count',
|
||||
'components_count',
|
||||
'licenses_count'
|
||||
'licenses_count',
|
||||
'notes',
|
||||
];
|
||||
|
||||
$manufacturers = Manufacturer::select([
|
||||
@@ -55,6 +56,7 @@ class ManufacturersController extends Controller
|
||||
'updated_at',
|
||||
'image',
|
||||
'deleted_at',
|
||||
'notes',
|
||||
])
|
||||
->with('adminuser')
|
||||
->withCount('assets as assets_count')
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\NoteAdded;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class NotesController extends Controller
|
||||
{
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'note' => 'required|string|max:500',
|
||||
'type' => [
|
||||
'required',
|
||||
Rule::in(['asset']),
|
||||
],
|
||||
]);
|
||||
|
||||
// This can be made dynamic by using $request->input('type') to determine which model type to add the note to.
|
||||
// For now, we are only placing this on Assets
|
||||
$item = Asset::findOrFail($request->input("id"));
|
||||
$this->authorize('update', $item);
|
||||
|
||||
event(new NoteAdded($item, Auth::user(), $validated['note']));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success'));
|
||||
}
|
||||
|
||||
public function update(Request $request)
|
||||
{
|
||||
|
||||
}
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use App\Models\License;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CurrentInventory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
@@ -80,7 +81,16 @@ class UsersController extends Controller
|
||||
'users.website',
|
||||
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations')
|
||||
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count');
|
||||
->withCount([
|
||||
'assets as assets_count' => function(Builder $query) {
|
||||
$query->withoutTrashed();
|
||||
},
|
||||
'licenses as licenses_count',
|
||||
'accessories as accessories_count',
|
||||
'consumables as consumables_count',
|
||||
'managesUsers as manages_users_count',
|
||||
'managedLocations as manages_locations_count'
|
||||
]);
|
||||
|
||||
|
||||
if ($request->filled('search') != '') {
|
||||
|
||||
@@ -44,10 +44,10 @@ class AssetModelsFilesController extends Controller
|
||||
$model->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,11 +119,10 @@ class AssetModelsFilesController extends Controller
|
||||
}
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the hardware management page
|
||||
|
||||
@@ -45,7 +45,7 @@ class AssetFilesController extends Controller
|
||||
$asset->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.upload.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
@@ -97,25 +97,19 @@ class AssetFilesController extends Controller
|
||||
*/
|
||||
public function destroy($assetId = null, $fileId = null) : RedirectResponse
|
||||
{
|
||||
$asset = Asset::find($assetId);
|
||||
$this->authorize('update', $asset);
|
||||
$rel_path = 'private_uploads/assets';
|
||||
|
||||
// the asset is valid
|
||||
if (isset($asset->id)) {
|
||||
if ($asset = Asset::find($assetId)) {
|
||||
$this->authorize('update', $asset);
|
||||
$log = Actionlog::find($fileId);
|
||||
if ($log) {
|
||||
$rel_path = 'private_uploads/assets';
|
||||
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
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()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
|
||||
}
|
||||
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
|
||||
@@ -535,10 +535,10 @@ class AssetsController extends Controller
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
if ($settings->qr_code == '1') {
|
||||
if (($settings->qr_code == '1') && ($settings->label2_2d_type !== 'none')) {
|
||||
$asset = Asset::withTrashed()->find($assetId);
|
||||
if ($asset) {
|
||||
$size = Helper::barcodeDimensions($settings->barcode_type);
|
||||
$size = Helper::barcodeDimensions($settings->label2_2d_type);
|
||||
$qr_file = public_path().'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png';
|
||||
|
||||
if (isset($asset->id, $asset->asset_tag)) {
|
||||
@@ -548,7 +548,7 @@ class AssetsController extends Controller
|
||||
return response()->file($qr_file, $header);
|
||||
} else {
|
||||
$barcode = new \Com\Tecnick\Barcode\Barcode();
|
||||
$barcode_obj = $barcode->getBarcodeObj($settings->barcode_type, route('hardware.show', $asset->id), $size['height'], $size['width'], 'black', [-2, -2, -2, -2]);
|
||||
$barcode_obj = $barcode->getBarcodeObj($settings->label2_2d_type, route('hardware.show', $asset->id), $size['height'], $size['width'], 'black', [-2, -2, -2, -2]);
|
||||
file_put_contents($qr_file, $barcode_obj->getPngData());
|
||||
|
||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||
@@ -573,7 +573,7 @@ class AssetsController extends Controller
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
if ($asset = Asset::withTrashed()->find($assetId)) {
|
||||
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
|
||||
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->label2_1d_type).'-'.str_slug($asset->asset_tag).'.png';
|
||||
|
||||
if (isset($asset->id, $asset->asset_tag)) {
|
||||
if (file_exists($barcode_file)) {
|
||||
@@ -586,7 +586,7 @@ class AssetsController extends Controller
|
||||
|
||||
$barcode = new \Com\Tecnick\Barcode\Barcode();
|
||||
try {
|
||||
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode, $asset->asset_tag, ($barcode_width < 300 ? $barcode_width : 300), 50);
|
||||
$barcode_obj = $barcode->getBarcodeObj($settings->label2_1d_type, $asset->asset_tag, ($barcode_width < 300 ? $barcode_width : 300), 50);
|
||||
file_put_contents($barcode_file, $barcode_obj->getPngData());
|
||||
|
||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||
@@ -865,8 +865,8 @@ class AssetsController extends Controller
|
||||
public function quickScan()
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
$dt = Carbon::now()->addMonths(12)->toDateString();
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||
return view('hardware/quickscan')->with('next_audit_date', $dt);
|
||||
}
|
||||
|
||||
@@ -883,7 +883,6 @@ class AssetsController extends Controller
|
||||
$this->authorize('audit', Asset::class);
|
||||
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||
$asset = Asset::findOrFail($id);
|
||||
|
||||
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,14 @@ class ForgotPasswordController extends Controller
|
||||
*/
|
||||
public function sendResetLinkEmail(Request $request)
|
||||
{
|
||||
|
||||
/**
|
||||
* Let's set a max character count here to prevent potential
|
||||
* buffer overflow issues with attackers sending very large
|
||||
* payloads through.
|
||||
* payloads through. The addition of the string rule prevents attackers
|
||||
* sending arrays through and causing 500s
|
||||
*/
|
||||
$request->validate([
|
||||
'username' => ['required', 'max:255'],
|
||||
'username' => ['required', 'max:255', 'string'],
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,22 +103,24 @@ class ResetPasswordController extends Controller
|
||||
], $messages);
|
||||
}
|
||||
|
||||
if ($user->ldap_import != '1') {
|
||||
|
||||
// set the response
|
||||
$response = $broker->reset(
|
||||
$this->credentials($request), function ($user, $password) {
|
||||
$this->resetPassword($user, $password);
|
||||
});
|
||||
// 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'));
|
||||
// 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('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('success', trans('passwords.reset'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ class CategoriesController extends Controller
|
||||
$category->use_default_eula = $request->input('use_default_eula', '0');
|
||||
$category->require_acceptance = $request->input('require_acceptance', '0');
|
||||
$category->checkin_email = $request->input('checkin_email', '0');
|
||||
$category->notes = $request->input('notes');
|
||||
$category->created_by = auth()->id();
|
||||
|
||||
$category = $request->handleImages($category);
|
||||
@@ -134,6 +135,7 @@ class CategoriesController extends Controller
|
||||
$category->use_default_eula = $request->input('use_default_eula', '0');
|
||||
$category->require_acceptance = $request->input('require_acceptance', '0');
|
||||
$category->checkin_email = $request->input('checkin_email', '0');
|
||||
$category->notes = $request->input('notes');
|
||||
|
||||
$category = $request->handleImages($category);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ final class CompaniesController extends Controller
|
||||
$company->phone = $request->input('phone');
|
||||
$company->fax = $request->input('fax');
|
||||
$company->email = $request->input('email');
|
||||
$company->notes = $request->input('notes');
|
||||
$company->created_by = auth()->id();
|
||||
|
||||
$company = $request->handleImages($company);
|
||||
@@ -111,6 +112,7 @@ final class CompaniesController extends Controller
|
||||
$company->phone = $request->input('phone');
|
||||
$company->fax = $request->input('fax');
|
||||
$company->email = $request->input('email');
|
||||
$company->notes = $request->input('notes');
|
||||
|
||||
$company = $request->handleImages($company);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class ComponentsFilesController extends Controller
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('components.show', $component->id)->with('success', trans('general.file_upload_success'));
|
||||
return redirect()->route('components.show', $component->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class ComponentsFilesController extends Controller
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
return redirect()->back()->withFragment('files')
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class ConsumablesController extends Controller
|
||||
{
|
||||
$this->authorize('create', Consumable::class);
|
||||
|
||||
return view('consumables/edit')->with('category_type', 'consumable')
|
||||
return view('consumables.edit')->with('category_type', 'consumable')
|
||||
->with('item', new Consumable);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class ConsumablesFilesController extends Controller
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('consumables.show', $consumable->id)->with('success', trans('general.file_upload_success'));
|
||||
return redirect()->route('consumables.show', $consumable->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class ConsumablesFilesController extends Controller
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
return redirect()->back()->withFragment('files')
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class CustomFieldsController extends Controller
|
||||
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
|
||||
"show_in_listview" => $request->get("show_in_listview", 0),
|
||||
"show_in_requestable_list" => $request->get("show_in_requestable_list", 0),
|
||||
"user_id" => auth()->id()
|
||||
"created_by" => auth()->id()
|
||||
]);
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ class DepartmentsController extends Controller
|
||||
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
|
||||
$department->location_id = ($request->filled('location_id') ? $request->input('location_id') : null);
|
||||
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
|
||||
$department->notes = $request->input('notes');
|
||||
$department = $request->handleImages($department);
|
||||
|
||||
if ($department->save()) {
|
||||
@@ -171,7 +172,7 @@ class DepartmentsController extends Controller
|
||||
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
|
||||
$department->phone = $request->input('phone');
|
||||
$department->fax = $request->input('fax');
|
||||
|
||||
$department->notes = $request->input('notes');
|
||||
$department = $request->handleImages($department);
|
||||
|
||||
if ($department->save()) {
|
||||
|
||||
@@ -62,6 +62,7 @@ class GroupsController extends Controller
|
||||
$group->name = $request->input('name');
|
||||
$group->permissions = json_encode($request->input('permission'));
|
||||
$group->created_by = auth()->id();
|
||||
$group->notes = $request->input('notes');
|
||||
|
||||
if ($group->save()) {
|
||||
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
|
||||
@@ -108,6 +109,7 @@ class GroupsController extends Controller
|
||||
}
|
||||
$group->name = $request->input('name');
|
||||
$group->permissions = json_encode($request->input('permission'));
|
||||
$group->notes = $request->input('notes');
|
||||
|
||||
if (! config('app.lock_passwords')) {
|
||||
if ($group->save()) {
|
||||
|
||||
@@ -71,7 +71,7 @@ class LicenseCheckinController extends Controller
|
||||
|
||||
if (! $license->reassignable) {
|
||||
// Not allowed to checkin
|
||||
Session::flash('error', 'License not reassignable.');
|
||||
Session::flash('error', trans('admin/licenses/message.checkin.not_reassignable') . '.');
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ class LocationsController extends Controller
|
||||
$location->created_by = auth()->id();
|
||||
$location->phone = request('phone');
|
||||
$location->fax = request('fax');
|
||||
$location->notes = $request->input('notes');
|
||||
|
||||
$location = $request->handleImages($location);
|
||||
|
||||
@@ -138,6 +139,7 @@ class LocationsController extends Controller
|
||||
$location->fax = request('fax');
|
||||
$location->ldap_ou = $request->input('ldap_ou');
|
||||
$location->manager_id = $request->input('manager_id');
|
||||
$location->notes = $request->input('notes');
|
||||
|
||||
$location = $request->handleImages($location);
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ class ManufacturersController extends Controller
|
||||
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
|
||||
$manufacturer->support_phone = $request->input('support_phone');
|
||||
$manufacturer->support_email = $request->input('support_email');
|
||||
$manufacturer->notes = $request->input('notes');
|
||||
$manufacturer = $request->handleImages($manufacturer);
|
||||
|
||||
if ($manufacturer->save()) {
|
||||
@@ -123,6 +124,7 @@ class ManufacturersController extends Controller
|
||||
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
|
||||
$manufacturer->support_phone = $request->input('support_phone');
|
||||
$manufacturer->support_email = $request->input('support_email');
|
||||
$manufacturer->notes = $request->input('notes');
|
||||
|
||||
// Set the model's image property to null if the image is being deleted
|
||||
if ($request->input('image_delete') == 1) {
|
||||
|
||||
@@ -32,7 +32,8 @@ class ModalController extends Controller
|
||||
'statuslabel',
|
||||
'supplier',
|
||||
'upload-file',
|
||||
'user',
|
||||
'user',
|
||||
'add-note',
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -99,9 +99,13 @@ class ProfileController extends Controller
|
||||
* User change email page.
|
||||
*
|
||||
*/
|
||||
public function password() : View
|
||||
public function password() : View | RedirectResponse
|
||||
{
|
||||
|
||||
$user = auth()->user();
|
||||
if ($user->ldap_import=='1') {
|
||||
return redirect()->route('account')->with('error', trans('admin/users/message.error.password_ldap'));
|
||||
}
|
||||
return view('account/change-password', compact('user'));
|
||||
}
|
||||
|
||||
@@ -116,7 +120,7 @@ class ProfileController extends Controller
|
||||
|
||||
$user = auth()->user();
|
||||
if ($user->ldap_import == '1') {
|
||||
return redirect()->route('account.password.index')->with('error', trans('admin/users/message.error.password_ldap'));
|
||||
return redirect()->route('account')->with('error', trans('admin/users/message.error.password_ldap'));
|
||||
}
|
||||
|
||||
$rules = [
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use App\Models\ReportTemplate;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class ReportTemplatesController extends Controller
|
||||
{
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
// Ignore "options" rules since data does not come in under that key...
|
||||
$validated = $request->validate(Arr::except((new ReportTemplate)->getRules(), 'options'));
|
||||
|
||||
$report = $request->user()->reportTemplates()->create([
|
||||
'name' => $validated['name'],
|
||||
'options' => $request->except(['_token', 'name']),
|
||||
]);
|
||||
|
||||
session()->flash('success', trans('admin/reports/message.create.success'));
|
||||
|
||||
return redirect()->route('report-templates.show', $report->id);
|
||||
}
|
||||
|
||||
public function show(ReportTemplate $reportTemplate)
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
$customfields = CustomField::get();
|
||||
$report_templates = ReportTemplate::orderBy('name')->get();
|
||||
|
||||
return view('reports/custom', [
|
||||
'customfields' => $customfields,
|
||||
'report_templates' => $report_templates,
|
||||
'template' => $reportTemplate,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(ReportTemplate $reportTemplate)
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
return view('reports/custom', [
|
||||
'customfields' => CustomField::get(),
|
||||
'template' => $reportTemplate,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, ReportTemplate $reportTemplate): RedirectResponse
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
// Ignore "options" rules since data does not come in under that key...
|
||||
$validated = $request->validate(Arr::except((new ReportTemplate)->getRules(), 'options'));
|
||||
|
||||
$reportTemplate->update([
|
||||
'name' => $validated['name'],
|
||||
'options' => $request->except(['_token', 'name']),
|
||||
]);
|
||||
|
||||
session()->flash('success', trans('admin/reports/message.update.success'));
|
||||
|
||||
return redirect()->route('report-templates.show', $reportTemplate->id);
|
||||
}
|
||||
|
||||
public function destroy(ReportTemplate $reportTemplate): RedirectResponse
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
$reportTemplate->delete();
|
||||
|
||||
return redirect()->route('reports/custom')
|
||||
->with('success', trans('admin/reports/message.delete.success'));
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,15 @@ use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Depreciation;
|
||||
use App\Models\License;
|
||||
use App\Models\ReportTemplate;
|
||||
use App\Models\Setting;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
@@ -394,12 +397,27 @@ class ReportsController extends Controller
|
||||
* @see ReportsController::postCustomReport() method that generates the CSV
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function getCustomReport() : View
|
||||
public function getCustomReport(Request $request) : View
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
$customfields = CustomField::get();
|
||||
$report_templates = ReportTemplate::orderBy('name')->get();
|
||||
|
||||
return view('reports/custom')->with('customfields', $customfields);
|
||||
// The view needs a template to render correctly, even if it is empty...
|
||||
$template = new ReportTemplate;
|
||||
|
||||
// Set the report's input values in the cases we were redirected back
|
||||
// with validation errors so the report is populated as expected.
|
||||
if ($request->old()) {
|
||||
$template->name = $request->old('name');
|
||||
$template->options = $request->old();
|
||||
}
|
||||
|
||||
return view('reports/custom', [
|
||||
'customfields' => $customfields,
|
||||
'report_templates' => $report_templates,
|
||||
'template' => $template,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1093,28 +1111,31 @@ class ReportsController extends Controller
|
||||
$this->authorize('reports.view');
|
||||
$showDeleted = $deleted == 'deleted';
|
||||
|
||||
/**
|
||||
* Get all assets with pending checkout acceptances
|
||||
*/
|
||||
if($showDeleted) {
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
} else {
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->with(['assignedTo' => function ($query) {
|
||||
$query->withTrashed();
|
||||
}, 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
$query = CheckoutAcceptance::pending()
|
||||
->where('checkoutable_type', 'App\Models\Asset')
|
||||
->with([
|
||||
'checkoutable' => function (MorphTo $query) {
|
||||
$query->morphWith([
|
||||
AssetModel::class => ['model'],
|
||||
Company::class => ['company'],
|
||||
Asset::class => ['assignedTo'],
|
||||
])->with('model.category');
|
||||
},
|
||||
'assignedTo' => function($query){
|
||||
$query->withTrashed();
|
||||
}
|
||||
]);
|
||||
|
||||
if ($showDeleted) {
|
||||
$query->withTrashed();
|
||||
}
|
||||
|
||||
$assetsForReport = $acceptances
|
||||
->filter(function ($acceptance) {
|
||||
$acceptance_checkoutable_flag = false;
|
||||
if ($acceptance->checkoutable){
|
||||
$acceptance_checkoutable_flag = $acceptance->checkoutable->checkedOutToUser();
|
||||
}
|
||||
|
||||
return $acceptance->checkoutable_type == 'App\Models\Asset' && $acceptance_checkoutable_flag;
|
||||
})
|
||||
->map(function($acceptance) {
|
||||
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
|
||||
$assetsForReport = $query->get()
|
||||
->map(function ($acceptance) {
|
||||
return [
|
||||
'assetItem' => $acceptance->checkoutable,
|
||||
'acceptance' => $acceptance,
|
||||
];
|
||||
});
|
||||
|
||||
return view('reports/unaccepted_assets', compact('assetsForReport','showDeleted' ));
|
||||
@@ -1156,10 +1177,10 @@ class ReportsController extends Controller
|
||||
$locale = $assetItem->assignedTo?->locale;
|
||||
// Only send notification if assigned
|
||||
if ($locale && $email) {
|
||||
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $logItem->note, $acceptance))->locale($locale));
|
||||
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note))->locale($locale));
|
||||
|
||||
} elseif ($email) {
|
||||
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $logItem->note, $acceptance)));
|
||||
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)));
|
||||
}
|
||||
|
||||
if ($email == ''){
|
||||
|
||||
@@ -192,6 +192,7 @@ class SettingsController extends Controller
|
||||
$settings->next_auto_tag_base = 1;
|
||||
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
|
||||
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
|
||||
$settings->zerofill_count = $request->input('zerofill_count') ?: 0;
|
||||
|
||||
if ((! $user->isValid()) || (! $settings->isValid())) {
|
||||
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
|
||||
@@ -695,48 +696,6 @@ class SettingsController extends Controller
|
||||
return redirect()->back()->withInput()->withErrors($setting->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form to allow a super admin to update settings.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function getBarcodes() : View
|
||||
{
|
||||
$setting = Setting::getSettings();
|
||||
$is_gd_installed = extension_loaded('gd');
|
||||
|
||||
return view('settings.barcodes', compact('setting'))->with('is_gd_installed', $is_gd_installed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves settings from form.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function postBarcodes(Request $request) : RedirectResponse
|
||||
{
|
||||
if (is_null($setting = Setting::getSettings())) {
|
||||
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
|
||||
}
|
||||
|
||||
$setting->qr_code = $request->input('qr_code', '0');
|
||||
$setting->alt_barcode = $request->input('alt_barcode');
|
||||
$setting->alt_barcode_enabled = $request->input('alt_barcode_enabled', '0');
|
||||
$setting->barcode_type = $request->input('barcode_type');
|
||||
$setting->qr_text = $request->input('qr_text');
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
->with('success', trans('admin/settings/message.update.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($setting->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form to allow a super admin to update settings.
|
||||
*
|
||||
@@ -762,8 +721,11 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function getLabels() : View
|
||||
{
|
||||
$is_gd_installed = extension_loaded('gd');
|
||||
|
||||
return view('settings.labels')
|
||||
->with('setting', Setting::getSettings())
|
||||
->with('is_gd_installed', $is_gd_installed)
|
||||
->with('customFields', CustomField::where('field_encrypted', '=', 0)->get());
|
||||
}
|
||||
|
||||
@@ -799,9 +761,13 @@ class SettingsController extends Controller
|
||||
$setting->labels_pagewidth = $request->input('labels_pagewidth');
|
||||
$setting->labels_pageheight = $request->input('labels_pageheight');
|
||||
$setting->labels_display_company_name = $request->input('labels_display_company_name', '0');
|
||||
$setting->labels_display_company_name = $request->input('labels_display_company_name', '0');
|
||||
|
||||
|
||||
//Barcodes
|
||||
$setting->qr_code = $request->input('qr_code', '0');
|
||||
//1D-Barcode
|
||||
$setting->alt_barcode_enabled = $request->input('alt_barcode_enabled', '0');
|
||||
//QR-Code
|
||||
$setting->qr_text = $request->input('qr_text');
|
||||
|
||||
if ($request->filled('labels_display_name')) {
|
||||
$setting->labels_display_name = 1;
|
||||
@@ -834,6 +800,7 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
if ($setting->save()) {
|
||||
|
||||
return redirect()->route('settings.labels.index')
|
||||
->with('success', trans('admin/settings/message.update.success'));
|
||||
}
|
||||
@@ -903,7 +870,6 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
if ($setting->save()) {
|
||||
$setting->update_client_side_cert_files();
|
||||
return redirect()->route('settings.ldap.index')
|
||||
->with('success', trans('admin/settings/message.update.success'));
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class BulkUsersController extends Controller
|
||||
// bulk password reset, just do the thing
|
||||
} elseif ($request->input('bulk_actions') == 'bulkpasswordreset') {
|
||||
foreach ($users as $user) {
|
||||
if (($user->activated == '1') && ($user->email != '')) {
|
||||
if (($user->activated == '1') && ($user->email != '') && ($user->ldap_import != '1')) {
|
||||
$credentials = ['email' => $user->email];
|
||||
Password::sendResetLink($credentials/* , function (Message $message) {
|
||||
$message->subject($this->getEmailSubject()); // TODO - I'm not sure if we still need this, but this second parameter is no longer accepted in later Laravel versions.
|
||||
|
||||
@@ -56,7 +56,7 @@ class UserFilesController extends Controller
|
||||
$logActions[] = $logAction;
|
||||
}
|
||||
// dd($logActions);
|
||||
return redirect()->back()->with('success', trans('admin/users/message.upload.success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.upload.success'));
|
||||
}
|
||||
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
|
||||
|
||||
@@ -87,7 +87,7 @@ class UserFilesController extends Controller
|
||||
|
||||
if (Storage::exists($rel_path.'/'.$filename)) {
|
||||
Storage::delete($rel_path.'/'.$filename);
|
||||
return redirect()->back()->with('success', trans('admin/users/message.deletefile.success'));
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.deletefile.success'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ class AssetCheckoutRequest extends Request
|
||||
$settings = \App\Models\Setting::getSettings();
|
||||
|
||||
$rules = [
|
||||
'assigned_user' => 'required_without_all:assigned_asset,assigned_location',
|
||||
'assigned_asset' => 'required_without_all:assigned_user,assigned_location',
|
||||
'assigned_location' => 'required_without_all:assigned_user,assigned_asset',
|
||||
'assigned_user' => 'numeric|nullable|required_without_all:assigned_asset,assigned_location',
|
||||
'assigned_asset' => 'numeric|nullable|required_without_all:assigned_user,assigned_location',
|
||||
'assigned_location' => 'numeric|nullable|required_without_all:assigned_user,assigned_asset',
|
||||
'status_id' => 'exists:status_labels,id,deployable,1',
|
||||
'checkout_to_type' => 'required|in:asset,location,user',
|
||||
'checkout_at' => [
|
||||
|
||||
@@ -62,7 +62,7 @@ class SettingsSamlRequest extends FormRequest
|
||||
$custom_privateKey = '';
|
||||
$custom_x509certNew = '';
|
||||
if (! empty($this->input('saml_custom_settings'))) {
|
||||
$req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings'));
|
||||
$req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings', ''));
|
||||
$custom_settings = [];
|
||||
|
||||
foreach ($req_custom_settings as $custom_setting) {
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
|
||||
use App\Models\Labels\Label;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreLabelSettings extends FormRequest
|
||||
{
|
||||
@@ -22,6 +25,10 @@ class StoreLabelSettings extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$names = Label::find()?->map(function ($label) {
|
||||
return $label->getName();
|
||||
})->values()->toArray();
|
||||
|
||||
return [
|
||||
'labels_per_page' => 'numeric',
|
||||
'labels_width' => 'numeric',
|
||||
@@ -36,6 +43,10 @@ class StoreLabelSettings extends FormRequest
|
||||
'labels_pagewidth' => 'numeric|nullable',
|
||||
'labels_pageheight' => 'numeric|nullable',
|
||||
'qr_text' => 'max:31|nullable',
|
||||
'label2_template' => [
|
||||
'required',
|
||||
Rule::in($names),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ class UploadFileRequest extends Request
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$file_name = $name_prefix.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$file->guessExtension();
|
||||
|
||||
|
||||
Log::debug("Your filetype IS: ".$file->getMimeType());
|
||||
// Check for SVG and sanitize it
|
||||
if ($file->getMimeType() === 'image/svg+xml') {
|
||||
Log::debug('This is an SVG');
|
||||
@@ -66,7 +64,6 @@ class UploadFileRequest extends Request
|
||||
|
||||
} else {
|
||||
$put_results = Storage::put($dirname.$file_name, file_get_contents($file));
|
||||
Log::debug("Here are the '$put_results' (should be 0 or 1 or true or false or something?)");
|
||||
}
|
||||
return $file_name;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class AccessoriesTransformer
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $total)
|
||||
public function transformCheckedoutAccessory($accessory_checkouts, $total)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
@@ -77,9 +77,13 @@ class AccessoriesTransformer
|
||||
$array[] = [
|
||||
'id' => $checkout->id,
|
||||
'assigned_to' => $this->transformAssignedTo($checkout),
|
||||
'checkout_notes' => e($checkout->note),
|
||||
'last_checkout' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
|
||||
'available_actions' => ['checkin' => true],
|
||||
'note' => $checkout->note ? e($checkout->note) : null,
|
||||
'created_by' => $checkout->adminuser ? [
|
||||
'id' => (int) $checkout->adminuser->id,
|
||||
'name'=> e($checkout->adminuser->present()->fullName),
|
||||
]: null,
|
||||
'created_at' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
|
||||
'available_actions' => Gate::allows('checkout', Accessory::class) ? ['checkin' => true] : ['checkin' => false],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -89,22 +93,11 @@ class AccessoriesTransformer
|
||||
public function transformAssignedTo($accessoryCheckout)
|
||||
{
|
||||
if ($accessoryCheckout->checkedOutToUser()) {
|
||||
return [
|
||||
'id' => (int) $accessoryCheckout->assigned->id,
|
||||
'username' => e($accessoryCheckout->assigned->username),
|
||||
'name' => e($accessoryCheckout->assigned->getFullNameAttribute()),
|
||||
'first_name'=> e($accessoryCheckout->assigned->first_name),
|
||||
'last_name'=> ($accessoryCheckout->assigned->last_name) ? e($accessoryCheckout->assigned->last_name) : null,
|
||||
'email'=> ($accessoryCheckout->assigned->email) ? e($accessoryCheckout->assigned->email) : null,
|
||||
'employee_number' => ($accessoryCheckout->assigned->employee_num) ? e($accessoryCheckout->assigned->employee_num) : null,
|
||||
'type' => 'user',
|
||||
];
|
||||
return (new UsersTransformer)->transformUserCompact($accessoryCheckout->assigned);
|
||||
} elseif ($accessoryCheckout->checkedOutToLocation()) {
|
||||
return (new LocationsTransformer())->transformLocationCompact($accessoryCheckout->assigned);
|
||||
} elseif ($accessoryCheckout->checkedOutToAsset()) {
|
||||
return (new AssetsTransformer())->transformAssetCompact($accessoryCheckout->assigned);
|
||||
}
|
||||
|
||||
return $accessoryCheckout->assigned ? [
|
||||
'id' => $accessoryCheckout->assigned->id,
|
||||
'name' => e($accessoryCheckout->assigned->display_name),
|
||||
'type' => $accessoryCheckout->assignedType(),
|
||||
] : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,15 @@ class AssetMaintenancesTransformer
|
||||
'name'=> ($assetmaintenance->asset->name) ? e($assetmaintenance->asset->name) : null,
|
||||
'asset_tag'=> e($assetmaintenance->asset->asset_tag),
|
||||
'serial'=> e($assetmaintenance->asset->serial),
|
||||
'deleted_at'=> e($assetmaintenance->asset->deleted_at),
|
||||
'created_at'=> e($assetmaintenance->asset->created_at),
|
||||
'deleted_at'=> Helper::getFormattedDateObject($assetmaintenance->asset->deleted_at, 'datetime'),
|
||||
'created_at' => Helper::getFormattedDateObject($assetmaintenance->asset->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($assetmaintenance->asset->updated_at, 'datetime'),
|
||||
] : null,
|
||||
'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [
|
||||
'id' => (int) $assetmaintenance->asset->model->id,
|
||||
'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null,
|
||||
] : null,
|
||||
'status_label' => ($assetmaintenance->asset->assetstatus) ? [
|
||||
'status_label' => (($assetmaintenance->asset) && ($assetmaintenance->asset->assetstatus)) ? [
|
||||
'id' => (int) $assetmaintenance->asset->assetstatus->id,
|
||||
'name'=> e($assetmaintenance->asset->assetstatus->name),
|
||||
'status_type'=> e($assetmaintenance->asset->assetstatus->getStatuslabelType()),
|
||||
@@ -79,7 +80,7 @@ class AssetMaintenancesTransformer
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => (Gate::allows('update', Asset::class) && ($assetmaintenance->asset->deleted_at=='')) ? true : false,
|
||||
'update' => (Gate::allows('update', Asset::class) && ((($assetmaintenance->asset) && $assetmaintenance->asset->deleted_at==''))) ? true : false,
|
||||
'delete' => Gate::allows('delete', Asset::class),
|
||||
];
|
||||
|
||||
|
||||
@@ -87,6 +87,41 @@ class AssetModelsTransformer
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function transformAssetModelFiles($assetmodel, $total)
|
||||
{
|
||||
|
||||
$array = [];
|
||||
foreach ($assetmodel->uploads as $file) {
|
||||
$array[] = self::transformAssetModelFile($file, $assetmodel);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformAssetModelFile($file, $assetmodel)
|
||||
{
|
||||
|
||||
$array = [
|
||||
'id' => (int) $file->id,
|
||||
'filename' => e($file->filename),
|
||||
'url' => route('show/modelfile', [$assetmodel->id, $file->id]),
|
||||
'created_by' => ($file->adminuser) ? [
|
||||
'id' => (int) $file->adminuser->id,
|
||||
'name'=> e($file->adminuser->present()->fullName),
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($file->updated_at, 'datetime'),
|
||||
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'delete' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at == '')),
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function transformAssetModelsDatatable($assetmodels)
|
||||
{
|
||||
return (new DatatablesTransformer)->transformDatatables($assetmodels);
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AssetsTransformer
|
||||
{
|
||||
@@ -225,7 +227,7 @@ class AssetsTransformer
|
||||
public function transformRequestedAsset(Asset $asset)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $asset->id,
|
||||
'id' => (int)$asset->id,
|
||||
'name' => e($asset->name),
|
||||
'asset_tag' => e($asset->asset_tag),
|
||||
'serial' => e($asset->serial),
|
||||
@@ -234,7 +236,7 @@ class AssetsTransformer
|
||||
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
|
||||
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
|
||||
'location' => ($asset->location) ? e($asset->location->name) : null,
|
||||
'status'=> ($asset->assetstatus) ? $asset->present()->statusMeta : null,
|
||||
'status' => ($asset->assetstatus) ? $asset->present()->statusMeta : null,
|
||||
'assigned_to_self' => ($asset->assigned_to == auth()->id()),
|
||||
];
|
||||
|
||||
@@ -244,7 +246,7 @@ class AssetsTransformer
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
|
||||
// Only display this if it's allowed via the custom field setting
|
||||
if (($field->field_encrypted=='0') && ($field->show_in_requestable_list=='1')) {
|
||||
if (($field->field_encrypted == '0') && ($field->show_in_requestable_list == '1')) {
|
||||
|
||||
$value = $asset->{$field->db_column};
|
||||
if (($field->format == 'DATE') && (!is_null($value)) && ($value != '')) {
|
||||
@@ -268,7 +270,61 @@ class AssetsTransformer
|
||||
|
||||
$array += $permissions_array;
|
||||
return $array;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function transformAssetCompact(Asset $asset)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $asset->id,
|
||||
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
|
||||
'type' => 'asset',
|
||||
'name' => e($asset->present()->fullName()),
|
||||
'model' => ($asset->model) ? e($asset->model->name) : null,
|
||||
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
|
||||
'asset_tag' => e($asset->asset_tag),
|
||||
'serial' => e($asset->serial),
|
||||
];
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function transformCheckedoutAccessories($accessory_checkouts, $total)
|
||||
{
|
||||
|
||||
$array = [];
|
||||
foreach ($accessory_checkouts as $checkout) {
|
||||
$array[] = self::transformCheckedoutAccessory($checkout);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
|
||||
public function transformCheckedoutAccessory(AccessoryCheckout $accessory_checkout)
|
||||
{
|
||||
|
||||
$array = [
|
||||
'id' => $accessory_checkout->id,
|
||||
'accessory' => [
|
||||
'id' => $accessory_checkout->accessory->id,
|
||||
'name' => $accessory_checkout->accessory->name,
|
||||
],
|
||||
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory_checkout->accessory->image)) : null,
|
||||
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
|
||||
'created_by' => $accessory_checkout->adminuser ? [
|
||||
'id' => (int) $accessory_checkout->adminuser->id,
|
||||
'name'=> e($accessory_checkout->adminuser->present()->fullName),
|
||||
]: null,
|
||||
'created_at' => Helper::getFormattedDateObject($accessory_checkout->created_at, 'datetime'),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'checkout' => false,
|
||||
'checkin' => Gate::allows('checkin', Accessory::class),
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
return $array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ class CategoriesTransformer
|
||||
'id' => (int) $category->adminuser->id,
|
||||
'name'=> e($category->adminuser->present()->fullName()),
|
||||
] : null,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($category->notes),
|
||||
'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -40,6 +40,7 @@ class CompaniesTransformer
|
||||
'id' => (int) $company->adminuser->id,
|
||||
'name'=> e($company->adminuser->present()->fullName()),
|
||||
] : null,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($company->notes),
|
||||
'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -44,6 +44,7 @@ class DepartmentsTransformer
|
||||
'name' => e($department->location->name),
|
||||
] : null,
|
||||
'users_count' => e($department->users_count),
|
||||
'notes' => Helper::parseEscapedMarkedownInline($department->notes),
|
||||
'created_at' => Helper::getFormattedDateObject($department->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($department->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -61,7 +61,7 @@ class DepreciationReportTransformer
|
||||
/**
|
||||
* Override the previously set null values if there is a valid model and associated depreciation
|
||||
*/
|
||||
if (($asset->model) && ($asset->model->depreciation)) {
|
||||
if (($asset->model) && ($asset->model->depreciation) && ($asset->model->depreciation->months !== 0)) {
|
||||
$depreciated_value = Helper::formatCurrencyOutput($asset->getDepreciatedValue());
|
||||
$monthly_depreciation =Helper::formatCurrencyOutput($asset->purchase_cost / $asset->model->depreciation->months);
|
||||
$diff = Helper::formatCurrencyOutput(($asset->purchase_cost - $asset->getDepreciatedValue()));
|
||||
|
||||
@@ -26,6 +26,7 @@ class GroupsTransformer
|
||||
'name' => e($group->name),
|
||||
'permissions' => json_decode($group->permissions),
|
||||
'users_count' => (int) $group->users_count,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($group->notes),
|
||||
'created_by' => ($group->adminuser) ? [
|
||||
'id' => (int) $group->adminuser->id,
|
||||
'name'=> e($group->adminuser->present()->fullName()),
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\Location;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@@ -45,12 +47,15 @@ class LocationsTransformer
|
||||
'zip' => ($location->zip) ? e($location->zip) : null,
|
||||
'phone' => ($location->phone!='') ? e($location->phone): null,
|
||||
'fax' => ($location->fax!='') ? e($location->fax): null,
|
||||
'accessories_count' => (int) $location->accessories_count,
|
||||
'assigned_accessories_count' => (int) $location->assigned_accessories_count,
|
||||
'assigned_assets_count' => (int) $location->assigned_assets_count,
|
||||
'assets_count' => (int) $location->assets_count,
|
||||
'rtd_assets_count' => (int) $location->rtd_assets_count,
|
||||
'users_count' => (int) $location->users_count,
|
||||
'currency' => ($location->currency) ? e($location->currency) : null,
|
||||
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
||||
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
|
||||
'parent' => ($location->parent) ? [
|
||||
@@ -76,4 +81,75 @@ class LocationsTransformer
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function transformCheckedoutAccessories($accessory_checkouts, $total)
|
||||
{
|
||||
|
||||
$array = [];
|
||||
foreach ($accessory_checkouts as $checkout) {
|
||||
$array[] = self::transformCheckedoutAccessory($checkout);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
|
||||
public function transformCheckedoutAccessory(AccessoryCheckout $accessory_checkout)
|
||||
{
|
||||
|
||||
$array = [
|
||||
'id' => $accessory_checkout->id,
|
||||
'accessory' => [
|
||||
'id' => $accessory_checkout->accessory->id,
|
||||
'name' => $accessory_checkout->accessory->name,
|
||||
],
|
||||
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory_checkout->accessory->image)) : null,
|
||||
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
|
||||
'created_by' => $accessory_checkout->adminuser ? [
|
||||
'id' => (int) $accessory_checkout->adminuser->id,
|
||||
'name'=> e($accessory_checkout->adminuser->present()->fullName),
|
||||
]: null,
|
||||
'created_at' => Helper::getFormattedDateObject($accessory_checkout->created_at, 'datetime'),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'checkout' => false,
|
||||
'checkin' => Gate::allows('checkin', Accessory::class),
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This gives a compact view of the location data without any additional relational queries,
|
||||
* allowing us to 1) deliver a smaller payload and 2) avoid additional queries on relations that
|
||||
* have not been easy/lazy loaded already
|
||||
*
|
||||
* @param Location $location
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function transformLocationCompact(Location $location = null)
|
||||
{
|
||||
if ($location) {
|
||||
|
||||
$array = [
|
||||
'id' => (int) $location->id,
|
||||
'image' => ($location->image) ? Storage::disk('public')->url('locations/'.e($location->image)) : null,
|
||||
'type' => "location",
|
||||
'name' => e($location->name),
|
||||
'created_by' => $location->adminuser ? [
|
||||
'id' => (int) $location->adminuser->id,
|
||||
'name'=> e($location->adminuser->present()->fullName),
|
||||
]: null,
|
||||
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
|
||||
];
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ class ManufacturersTransformer
|
||||
'consumables_count' => (int) $manufacturer->consumables_count,
|
||||
'accessories_count' => (int) $manufacturer->accessories_count,
|
||||
'components_count' => (int) $manufacturer->components_count,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($manufacturer->notes),
|
||||
'created_by' => ($manufacturer->adminuser) ? [
|
||||
'id' => (int) $manufacturer->adminuser->id,
|
||||
'name'=> e($manufacturer->adminuser->present()->fullName()),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\PredefinedKit;
|
||||
use App\Models\SnipeModel;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -42,7 +43,7 @@ class PredefinedKitsTransformer
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => Gate::allows('update', PredefinedKit::class),
|
||||
'delete' => Gate::allows('delete', PredefinedKit::class),
|
||||
'checkout' => Gate::allows('checkout', PredefinedKit::class),
|
||||
'checkout' => Gate::allows('checkout', Asset::class),
|
||||
// 'clone' => Gate::allows('create', PredefinedKit::class),
|
||||
// 'restore' => Gate::allows('create', PredefinedKit::class),
|
||||
];
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UsersTransformer
|
||||
{
|
||||
@@ -106,6 +106,37 @@ class UsersTransformer
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* This gives a compact view of the user data without any additional relational queries,
|
||||
* allowing us to 1) deliver a smaller payload and 2) avoid additional queries on relations that
|
||||
* have not been easy/lazy loaded already
|
||||
*
|
||||
* @param User $user
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function transformUserCompact(User $user) : array
|
||||
{
|
||||
|
||||
$array = [
|
||||
'id' => (int) $user->id,
|
||||
'image' => e($user->present()->gravatar) ?? null,
|
||||
'type' => 'user',
|
||||
'name' => e($user->getFullNameAttribute()),
|
||||
'first_name' => e($user->first_name),
|
||||
'last_name' => e($user->last_name),
|
||||
'username' => e($user->username),
|
||||
'created_by' => $user->adminuser ? [
|
||||
'id' => (int) $user->adminuser->id,
|
||||
'name'=> e($user->adminuser->present()->fullName),
|
||||
]: null,
|
||||
'created_at' => Helper::getFormattedDateObject($user->created_at, 'datetime'),
|
||||
'deleted_at' => ($user->deleted_at) ? Helper::getFormattedDateObject($user->deleted_at, 'datetime') : null,
|
||||
];
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function transformUsersDatatable($users)
|
||||
{
|
||||
return (new DatatablesTransformer)->transformDatatables($users);
|
||||
|
||||
@@ -39,6 +39,7 @@ abstract class Importer
|
||||
* @var array
|
||||
*/
|
||||
private $defaultFieldMap = [
|
||||
'id' => 'id',
|
||||
'asset_tag' => 'asset tag',
|
||||
'activated' => 'activated',
|
||||
'category' => 'category',
|
||||
|
||||
@@ -456,14 +456,13 @@ class ItemImporter extends Importer
|
||||
{
|
||||
if (empty($asset_location)) {
|
||||
$this->log('No location given, so none created.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$location = Location::where(['name' => $asset_location])->first();
|
||||
|
||||
if ($location) {
|
||||
$this->log('Location '.$asset_location.' already exists');
|
||||
|
||||
return $location->id;
|
||||
}
|
||||
// No matching locations in the collection, create a new one.
|
||||
|
||||
@@ -38,8 +38,16 @@ class LocationImporter extends ItemImporter
|
||||
{
|
||||
|
||||
$editingLocation = false;
|
||||
|
||||
$location = Location::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
|
||||
if ($this->findCsvMatch($row, 'id')!='') {
|
||||
// Override location if an ID was given
|
||||
\Log::debug('Finding location by ID: '.$this->findCsvMatch($row, 'id'));
|
||||
$location = Location::find($this->findCsvMatch($row, 'id'));
|
||||
}
|
||||
|
||||
|
||||
if ($location) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Location '.$this->item['name'].' already exists');
|
||||
@@ -66,6 +74,8 @@ class LocationImporter extends ItemImporter
|
||||
$this->item['ldap_ou'] = trim($this->findCsvMatch($row, 'ldap_ou'));
|
||||
$this->item['manager'] = trim($this->findCsvMatch($row, 'manager'));
|
||||
$this->item['manager_username'] = trim($this->findCsvMatch($row, 'manager_username'));
|
||||
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
|
||||
|
||||
|
||||
if ($this->findCsvMatch($row, 'parent_location')) {
|
||||
$this->item['parent_id'] = $this->createOrFetchLocation(trim($this->findCsvMatch($row, 'parent_location')));
|
||||
@@ -95,6 +105,7 @@ class LocationImporter extends ItemImporter
|
||||
|
||||
} else {
|
||||
Log::debug($location->getErrors());
|
||||
$this->logError($location, 'Location "'.$this->item['name'].'"');
|
||||
return $location->errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class CheckoutableListener
|
||||
*/
|
||||
public function onCheckedOut($event)
|
||||
{
|
||||
if ($this->shouldNotSendAnyNotifications($event->checkoutable)){
|
||||
if ($this->shouldNotSendAnyNotifications($event->checkoutable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class CheckoutableListener
|
||||
$acceptance = $this->getCheckoutAcceptance($event);
|
||||
$adminCcEmailsArray = [];
|
||||
|
||||
if($settings->admin_cc_email !== '') {
|
||||
if ($settings->admin_cc_email !== '') {
|
||||
$adminCcEmail = $settings->admin_cc_email;
|
||||
$adminCcEmailsArray = array_map('trim', explode(',', $adminCcEmail));
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class CheckoutableListener
|
||||
$mailable = $this->getCheckoutMailType($event, $acceptance);
|
||||
$notifiable = $this->getNotifiables($event);
|
||||
|
||||
if (!$event->checkedOutTo->locale){
|
||||
if ($event->checkedOutTo->locale) {
|
||||
$mailable->locale($event->checkedOutTo->locale);
|
||||
}
|
||||
// Send email notifications
|
||||
@@ -77,41 +77,56 @@ class CheckoutableListener
|
||||
* 3. The item should send an email at check-in/check-out
|
||||
*/
|
||||
|
||||
if ($event->checkoutable->requireAcceptance() || $event->checkoutable->getEula() ||
|
||||
$this->checkoutableShouldSendEmail($event)) {
|
||||
Log::info('Sending checkout email, Locale: ' . ($event->checkedOutTo->locale ?? 'default'));
|
||||
if (!empty($notifiable)) {
|
||||
Mail::to($notifiable)->cc($ccEmails)->send($mailable);
|
||||
} elseif (!empty($ccEmails)) {
|
||||
Mail::cc($ccEmails)->send($mailable);
|
||||
}
|
||||
Log::info('Checkout Mail sent.');
|
||||
if ($event->checkoutable->requireAcceptance() || $event->checkoutable->getEula() ||
|
||||
$this->checkoutableShouldSendEmail($event)) {
|
||||
Log::info('Sending checkout email, Locale: ' . ($event->checkedOutTo->locale ?? 'default'));
|
||||
if (!empty($notifiable)) {
|
||||
Mail::to($notifiable)->cc($ccEmails)->send($mailable);
|
||||
} elseif (!empty($ccEmails)) {
|
||||
Mail::cc($ccEmails)->send($mailable);
|
||||
}
|
||||
Log::info('Checkout Mail sent.');
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||
}
|
||||
// Send Webhook notification
|
||||
try{
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
||||
$message = $this->getCheckoutNotification($event)->toMicrosoftTeams();
|
||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
||||
} else {
|
||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event, $acceptance));
|
||||
}
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
||||
$message = $this->getCheckoutNotification($event)->toMicrosoftTeams();
|
||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
||||
} else {
|
||||
|
||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event, $acceptance));
|
||||
}
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
||||
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
|
||||
Log::warning(Setting::getSettings()->webhook_selected." notification failed: " . $e->getMessage());
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_channel_not_found') );
|
||||
}
|
||||
else {
|
||||
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
|
||||
}
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail') );
|
||||
} catch (Exception $e) {
|
||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
||||
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
|
||||
'error' => $e->getMessage(),
|
||||
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
|
||||
'event' => $event,
|
||||
]);
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Notify the user and post to webhook about the checked in checkoutable
|
||||
*/
|
||||
@@ -147,7 +162,7 @@ class CheckoutableListener
|
||||
$ccEmails = array_filter($adminCcEmailsArray);
|
||||
$mailable = $this->getCheckinMailType($event);
|
||||
$notifiable = $this->getNotifiables($event);
|
||||
if (!$event->checkedOutTo->locale){
|
||||
if ($event->checkedOutTo?->locale) {
|
||||
$mailable->locale($event->checkedOutTo->locale);
|
||||
}
|
||||
// Send email notifications
|
||||
@@ -178,18 +193,30 @@ class CheckoutableListener
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
||||
$message = $this->getCheckinNotification($event)->toMicrosoftTeams();
|
||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
||||
} else {
|
||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckinNotification($event));
|
||||
}
|
||||
$message = $this->getCheckinNotification($event)->toMicrosoftTeams();
|
||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
||||
} else {
|
||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckinNotification($event));
|
||||
}
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
Log::warning("Exception caught during checkin notification: " . $e->getMessage());
|
||||
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
|
||||
Log::warning(Setting::getSettings()->webhook_selected." notification failed: " . $e->getMessage());
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_channel_not_found') );
|
||||
}
|
||||
else {
|
||||
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::warning("Exception caught during checkin notification: " . $e->getMessage());
|
||||
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
|
||||
'error' => $e->getMessage(),
|
||||
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
|
||||
'event' => $event,
|
||||
]);
|
||||
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +309,7 @@ class CheckoutableListener
|
||||
];
|
||||
$mailable= $lookup[get_class($event->checkoutable)];
|
||||
|
||||
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $event->note, $acceptance);
|
||||
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note);
|
||||
|
||||
}
|
||||
private function getCheckinMailType($event){
|
||||
|
||||
@@ -17,6 +17,7 @@ use App\Events\ItemAccepted;
|
||||
use App\Events\ItemDeclined;
|
||||
use App\Events\LicenseCheckedIn;
|
||||
use App\Events\LicenseCheckedOut;
|
||||
use App\Events\NoteAdded;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\User;
|
||||
use App\Models\LicenseSeat;
|
||||
@@ -128,6 +129,23 @@ class LogListener
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note is added to action log
|
||||
*
|
||||
*/
|
||||
public function onNoteAdded(NoteAdded $event)
|
||||
{
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_id = $event->itemNoteAddedOn->id;
|
||||
$logaction->item_type = get_class($event->itemNoteAddedOn);
|
||||
$logaction->note = $event->note; //this is the received alphanumeric text from the box
|
||||
$logaction->created_by = $event->noteAddedBy->id;
|
||||
$logaction->action_type = 'note_added';
|
||||
$logaction->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*
|
||||
@@ -141,6 +159,7 @@ class LogListener
|
||||
'CheckoutAccepted',
|
||||
'CheckoutDeclined',
|
||||
'UserMerged',
|
||||
'NoteAdded',
|
||||
];
|
||||
|
||||
foreach ($list as $event) {
|
||||
|
||||
@@ -329,6 +329,7 @@ class Importer extends Component
|
||||
];
|
||||
|
||||
$this->locations_fields = [
|
||||
'id' => trans('general.id'),
|
||||
'name' => trans('general.item_name_var', ['item' => trans('general.location')]),
|
||||
'address' => trans('general.address'),
|
||||
'address2' => trans('general.importer.address2'),
|
||||
@@ -341,6 +342,7 @@ class Importer extends Component
|
||||
'manager_username' => trans('general.importer.manager_username'),
|
||||
'manager' => trans('general.importer.manager_full_name'),
|
||||
'parent_location' => trans('admin/locations/table.parent'),
|
||||
'notes' => trans('general.notes'),
|
||||
];
|
||||
|
||||
$this->assetmodels_fields = [
|
||||
@@ -400,7 +402,6 @@ class Importer extends Component
|
||||
'requestable',
|
||||
'Requestable',
|
||||
],
|
||||
|
||||
'gravatar' =>
|
||||
[
|
||||
'gravatar',
|
||||
|
||||
@@ -159,7 +159,7 @@ class SlackSettingsForm extends Component
|
||||
]);
|
||||
|
||||
try {
|
||||
$test = $webhook->post($this->webhook_endpoint, ['body' => $payload]);
|
||||
$test = $webhook->post($this->webhook_endpoint, ['body' => $payload, ['headers' => ['Content-Type' => 'application/json']]]);
|
||||
|
||||
if(($test->getStatusCode() == 302)||($test->getStatusCode() == 301)){
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error_redirect', ['endpoint' => $this->webhook_endpoint]));
|
||||
@@ -224,7 +224,7 @@ class SlackSettingsForm extends Component
|
||||
|
||||
try {
|
||||
$response = Http::withHeaders([
|
||||
'content-type' => 'applications/json',
|
||||
'content-type' => 'application/json',
|
||||
])->post($this->webhook_endpoint,
|
||||
$payload)->throw();
|
||||
|
||||
@@ -259,7 +259,7 @@ class SlackSettingsForm extends Component
|
||||
"text" => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
|
||||
];
|
||||
$response = Http::withHeaders([
|
||||
'content-type' => 'applications/json',
|
||||
'content-type' => 'application/json',
|
||||
])->post($this->webhook_endpoint,
|
||||
$payload)->throw();
|
||||
}
|
||||
@@ -269,7 +269,7 @@ class SlackSettingsForm extends Component
|
||||
$notification->success()->sendMessage($message);
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'content-type' => 'applications/json',
|
||||
'content-type' => 'application/json',
|
||||
])->post($this->webhook_endpoint);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class CheckoutAccessoryMail extends Mailable
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct(Accessory $accessory, $checkedOutTo, User $checkedOutBy,$note, $acceptance)
|
||||
public function __construct(Accessory $accessory, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->item = $accessory;
|
||||
$this->admin = $checkedOutBy;
|
||||
|
||||
@@ -23,7 +23,7 @@ class CheckoutAssetMail extends Mailable
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $note, $acceptance)
|
||||
public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->item = $asset;
|
||||
$this->admin = $checkedOutBy;
|
||||
|
||||
@@ -27,7 +27,6 @@ class CheckoutLicenseMail extends Mailable
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ExpiringAssetsMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct($params, $threshold)
|
||||
{
|
||||
$this->assets = $params;
|
||||
$this->threshold = $threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
$from = new Address(config('mail.from.address'), config('mail.from.name'));
|
||||
|
||||
return new Envelope(
|
||||
from: $from,
|
||||
subject: trans('mail.Expiring_Assets_Report'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'notifications.markdown.report-expiring-assets',
|
||||
with: [
|
||||
'assets' => $this->assets,
|
||||
'threshold' => $this->threshold,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ExpiringLicenseMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct($params, $threshold)
|
||||
{
|
||||
$this->licenses = $params;
|
||||
$this->threshold = $threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
$from = new Address(config('mail.from.address'), config('mail.from.name'));
|
||||
|
||||
return new Envelope(
|
||||
from: $from,
|
||||
subject: trans('mail.Expiring_Licenses_Report'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'notifications.markdown.report-expiring-licenses',
|
||||
with: [
|
||||
'licenses' => $this->licenses,
|
||||
'threshold' => $this->threshold,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,14 @@ class AccessoryCheckout extends Model
|
||||
{
|
||||
use Searchable;
|
||||
|
||||
protected $fillable = ['created_by', 'accessory_id', 'assigned_to', 'assigned_type', 'note'];
|
||||
protected $fillable = [
|
||||
'accessory_id',
|
||||
'assigned_to',
|
||||
'assigned_type',
|
||||
'note'
|
||||
];
|
||||
|
||||
protected $presenter = \App\Presenters\AccessoryPresenter::class;
|
||||
protected $table = 'accessories_checkout';
|
||||
|
||||
/**
|
||||
@@ -34,9 +41,13 @@ class AccessoryCheckout extends Model
|
||||
*/
|
||||
public function accessory()
|
||||
{
|
||||
return $this->hasOne(\App\Models\Accessory::class, 'accessory_id');
|
||||
return $this->hasOne(Accessory::class, 'id', 'accessory_id');
|
||||
}
|
||||
|
||||
public function accessories()
|
||||
{
|
||||
return $this->hasMany(Accessory::class, 'id', 'accessory_id');
|
||||
}
|
||||
/**
|
||||
* Establishes the accessory checkout -> user relationship
|
||||
*
|
||||
@@ -44,9 +55,9 @@ class AccessoryCheckout extends Model
|
||||
* @since [v7.0.9]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function user()
|
||||
public function adminuser()
|
||||
{
|
||||
return $this->hasOne(\App\Models\User::class, 'user_id');
|
||||
return $this->hasOne(\App\Models\User::class, 'created_by');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +87,7 @@ class AccessoryCheckout extends Model
|
||||
/**
|
||||
* Determines whether the accessory is checked out to a user
|
||||
*
|
||||
* Even though we allow allow for checkout to things beyond users
|
||||
* Even though we allow for checkout to things beyond users
|
||||
* this method is an easy way of seeing if we are checked out to a user.
|
||||
*
|
||||
* @author [A. Kroeger]
|
||||
@@ -84,7 +95,17 @@ class AccessoryCheckout extends Model
|
||||
*/
|
||||
public function checkedOutToUser(): bool
|
||||
{
|
||||
return $this->assignedType() === Asset::USER;
|
||||
return $this->assigned_type == User::class;
|
||||
}
|
||||
|
||||
public function checkedOutToLocation(): bool
|
||||
{
|
||||
return $this->assigned_type == Location::class;
|
||||
}
|
||||
|
||||
public function checkedOutToAsset(): bool
|
||||
{
|
||||
return $this->assigned_type == Asset::class;
|
||||
}
|
||||
|
||||
public function scopeUserAssigned(Builder $query): void
|
||||
@@ -92,6 +113,16 @@ class AccessoryCheckout extends Model
|
||||
$query->where('assigned_type', '=', User::class);
|
||||
}
|
||||
|
||||
public function scopeLocationAssigned(Builder $query): void
|
||||
{
|
||||
$query->where('assigned_type', '=', Location::class);
|
||||
}
|
||||
|
||||
public function scopeAssetAssigned(Builder $query): void
|
||||
{
|
||||
$query->where('assigned_type', '=', Asset::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run additional, advanced searches.
|
||||
*
|
||||
|
||||
@@ -69,7 +69,7 @@ class Actionlog extends SnipeModel
|
||||
'company' => ['name'],
|
||||
'adminuser' => ['first_name','last_name','username', 'email'],
|
||||
'user' => ['first_name','last_name','username', 'email'],
|
||||
'assets' => ['asset_tag','name'],
|
||||
'assets' => ['asset_tag','name', 'serial'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,6 +71,7 @@ class Category extends SnipeModel
|
||||
'require_acceptance',
|
||||
'use_default_eula',
|
||||
'created_by',
|
||||
'notes',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
@@ -80,7 +81,7 @@ class Category extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'category_type'];
|
||||
protected $searchableAttributes = ['name', 'category_type', 'notes'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
|
||||
@@ -35,7 +35,7 @@ class CheckoutAcceptance extends Model
|
||||
/**
|
||||
* The resource that was is out
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\MorphTo
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
|
||||
*/
|
||||
public function checkoutable()
|
||||
{
|
||||
|
||||
@@ -307,7 +307,7 @@ class CustomField extends Model
|
||||
public function formatFieldValuesAsArray()
|
||||
{
|
||||
$result = [];
|
||||
$arr = preg_split('/\\r\\n|\\r|\\n/', $this->field_values);
|
||||
$arr = preg_split('/\\r\\n|\\r|\\n/', $this->field_values ?? '');
|
||||
|
||||
if (($this->element != 'checkbox') && ($this->element != 'radio')) {
|
||||
$result[''] = 'Select '.strtolower($this->format);
|
||||
|
||||
@@ -141,4 +141,17 @@ class Department extends SnipeModel
|
||||
{
|
||||
return $query->leftJoin('users as department_user', 'departments.manager_id', '=', 'department_user.id')->orderBy('department_user.first_name', $order)->orderBy('department_user.last_name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on company
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param text $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderCompany($query, $order)
|
||||
{
|
||||
return $query->leftJoin('companies as company_sort', 'departments.company_id', '=', 'company_sort.id')->orderBy('company_sort.name', $order);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ class Group extends SnipeModel
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'permissions'
|
||||
'permissions',
|
||||
'notes',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ class Group extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'created_at'];
|
||||
protected $searchableAttributes = ['name', 'created_at', 'notes'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
|
||||
@@ -411,14 +411,14 @@ abstract class Label
|
||||
/**
|
||||
* Checks the template is internally valid
|
||||
*/
|
||||
public final function validate() {
|
||||
public final function validate() : void {
|
||||
$this->validateUnits();
|
||||
$this->validateSize();
|
||||
$this->validateMargins();
|
||||
$this->validateSupport();
|
||||
}
|
||||
|
||||
private function validateUnits() {
|
||||
private function validateUnits() : void {
|
||||
$validUnits = [ 'pt', 'mm', 'cm', 'in' ];
|
||||
$unit = $this->getUnit();
|
||||
if (!in_array(strtolower($unit), $validUnits)) {
|
||||
@@ -430,7 +430,7 @@ abstract class Label
|
||||
}
|
||||
}
|
||||
|
||||
private function validateSize() {
|
||||
private function validateSize() : void {
|
||||
$width = $this->getWidth();
|
||||
if (!is_numeric($width) || is_string($width)) {
|
||||
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
|
||||
@@ -450,7 +450,7 @@ abstract class Label
|
||||
}
|
||||
}
|
||||
|
||||
private function validateMargins() {
|
||||
private function validateMargins() : void {
|
||||
$marginTop = $this->getMarginTop();
|
||||
if (!is_numeric($marginTop) || is_string($marginTop)) {
|
||||
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
|
||||
@@ -488,7 +488,7 @@ abstract class Label
|
||||
}
|
||||
}
|
||||
|
||||
private function validateSupport() {
|
||||
private function validateSupport() : void {
|
||||
$support1D = $this->getSupport1DBarcode();
|
||||
if (!is_bool($support1D)) {
|
||||
throw new \UnexpectedValueException(trans('admin/labels/message.invalid_return_type', [
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Labels\Tapes\Brother;
|
||||
|
||||
class TZe_24mm_D extends TZe_24mm
|
||||
{
|
||||
private const BARCODE_MARGIN = 1.40;
|
||||
private const TAG_SIZE = 2.80;
|
||||
private const TITLE_SIZE = 2.80;
|
||||
private const TITLE_MARGIN = 0.50;
|
||||
private const LABEL_SIZE = 2.50;
|
||||
private const LABEL_MARGIN = - 0.35;
|
||||
private const FIELD_SIZE = 2.50;
|
||||
private const FIELD_MARGIN = 0.35;
|
||||
private const BARCODE1D_SIZE = 3.00; // Size for the C128 barcode at bottom
|
||||
|
||||
public function getUnit() { return 'mm'; }
|
||||
public function getWidth() { return 65.0; }
|
||||
public function getSupportAssetTag() { return true; }
|
||||
public function getSupport1DBarcode() { return true; }
|
||||
public function getSupport2DBarcode() { return true; }
|
||||
public function getSupportFields() { return 3; }
|
||||
public function getSupportLogo() { return false; }
|
||||
public function getSupportTitle() { return true; }
|
||||
|
||||
public function preparePDF($pdf) {}
|
||||
|
||||
public function write($pdf, $record) {
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$usableWidth = $pa->w;
|
||||
|
||||
// Reserve space at bottom for 1D barcode
|
||||
$usableHeight = $pa->h - self::BARCODE1D_SIZE;
|
||||
$barcodeSize = $usableHeight - self::TAG_SIZE;
|
||||
|
||||
if ($record->has('barcode2d')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE - self::BARCODE1D_SIZE,
|
||||
'freemono', 'b', self::TAG_SIZE, 'C',
|
||||
$barcodeSize, self::TAG_SIZE, true, 0
|
||||
);
|
||||
static::write2DBarcode(
|
||||
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
|
||||
$currentX, $currentY,
|
||||
$barcodeSize, $barcodeSize
|
||||
);
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
} else {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE - self::BARCODE1D_SIZE,
|
||||
'freemono', 'b', self::TAG_SIZE, 'R',
|
||||
$usableWidth, self::TAG_SIZE, true, 0
|
||||
);
|
||||
}
|
||||
|
||||
if ($record->has('title')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('title'),
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::TITLE_SIZE, 'L',
|
||||
$usableWidth, self::TITLE_SIZE, true, 0
|
||||
);
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
// Write label and value on the same line
|
||||
// Calculate label width with proportional character spacing
|
||||
$labelWidth = $pdf->GetStringWidth($field['label'], 'freemono', '', self::LABEL_SIZE);
|
||||
$charCount = strlen($field['label']);
|
||||
$spacingPerChar = 0.5;
|
||||
$totalSpacing = $charCount * $spacingPerChar;
|
||||
$adjustedWidth = $labelWidth + $totalSpacing;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', self::LABEL_SIZE, 'L',
|
||||
$adjustedWidth, self::LABEL_SIZE, true, 0, $spacingPerChar
|
||||
);
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX + $adjustedWidth + 2, $currentY,
|
||||
'freemono', 'B', self::FIELD_SIZE, 'L',
|
||||
$usableWidth - $adjustedWidth - 2, self::FIELD_SIZE, true, 0, 0.3
|
||||
);
|
||||
|
||||
$currentY += max(self::LABEL_SIZE, self::FIELD_SIZE) + self::FIELD_MARGIN;
|
||||
}
|
||||
|
||||
// Add C128 barcode at the bottom
|
||||
if ($record->has('barcode1d')) {
|
||||
static::write1DBarcode(
|
||||
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
|
||||
$pa->x1, $pa->y2 - self::BARCODE1D_SIZE,
|
||||
$pa->w, self::BARCODE1D_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -72,6 +72,7 @@ class Location extends SnipeModel
|
||||
'currency',
|
||||
'manager_id',
|
||||
'image',
|
||||
'notes',
|
||||
];
|
||||
protected $hidden = ['user_id'];
|
||||
|
||||
@@ -82,7 +83,7 @@ class Location extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'address', 'city', 'state', 'zip', 'created_at', 'ldap_ou', 'phone', 'fax'];
|
||||
protected $searchableAttributes = ['name', 'address', 'city', 'state', 'zip', 'created_at', 'ldap_ou', 'phone', 'fax', 'notes'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
@@ -253,6 +254,18 @@ class Location extends SnipeModel
|
||||
return $this->morphMany(\App\Models\Asset::class, 'assigned', 'assigned_type', 'assigned_to')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the accessory -> location assignment relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function assignedAccessories()
|
||||
{
|
||||
return $this->morphMany(\App\Models\AccessoryCheckout::class, 'assigned', 'assigned_type', 'assigned_to');
|
||||
}
|
||||
|
||||
public function setLdapOuAttribute($ldap_ou)
|
||||
{
|
||||
return $this->attributes['ldap_ou'] = empty($ldap_ou) ? null : $ldap_ou;
|
||||
|
||||
@@ -53,6 +53,7 @@ class Manufacturer extends SnipeModel
|
||||
'support_url',
|
||||
'url',
|
||||
'warranty_lookup_url',
|
||||
'notes',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
@@ -62,7 +63,7 @@ class Manufacturer extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'created_at'];
|
||||
protected $searchableAttributes = ['name', 'created_at', 'notes'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class ReportTemplate extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
use ValidatingTrait;
|
||||
|
||||
protected $casts = [
|
||||
'options' => 'array',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'created_by',
|
||||
'name',
|
||||
'options',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'options' => [
|
||||
'required',
|
||||
'array',
|
||||
],
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
// Scope to current user
|
||||
static::addGlobalScope('current_user', function (Builder $builder) {
|
||||
if (auth()->check()) {
|
||||
$builder->where('created_by', auth()->id());
|
||||
}
|
||||
});
|
||||
|
||||
static::created(function (ReportTemplate $reportTemplate) {
|
||||
$logAction = new Actionlog([
|
||||
'item_type' => ReportTemplate::class,
|
||||
'item_id' => $reportTemplate->id,
|
||||
'created_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
$logAction->logaction('create');
|
||||
});
|
||||
|
||||
static::updated(function (ReportTemplate $reportTemplate) {
|
||||
$changed = [];
|
||||
|
||||
foreach ($reportTemplate->getDirty() as $key => $value) {
|
||||
$changed[$key] = [
|
||||
'old' => $reportTemplate->getOriginal($key),
|
||||
'new' => $reportTemplate->getAttribute($key),
|
||||
];
|
||||
}
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = ReportTemplate::class;
|
||||
$logAction->item_id = $reportTemplate->id;
|
||||
$logAction->created_by = auth()->id();
|
||||
$logAction->log_meta = json_encode($changed);
|
||||
$logAction->logaction('update');
|
||||
});
|
||||
|
||||
static::deleted(function (ReportTemplate $reportTemplate) {
|
||||
$logAction = new Actionlog([
|
||||
'item_type' => ReportTemplate::class,
|
||||
'item_id' => $reportTemplate->id,
|
||||
'created_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
$logAction->logaction('delete');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the report template -> creator relationship.
|
||||
*
|
||||
*/
|
||||
public function creator(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a checkbox field for the given field name.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string $fallbackValue The value to return if the report template is not saved yet.
|
||||
*
|
||||
*/
|
||||
public function checkmarkValue(string $fieldName, string $fallbackValue = '1'): string
|
||||
{
|
||||
// Assuming we're using the null object pattern, and an empty model
|
||||
// was passed to the view when showing the default report page,
|
||||
// return the fallback value so that checkboxes are checked by default.
|
||||
if (is_null($this->id)) {
|
||||
return $fallbackValue;
|
||||
}
|
||||
|
||||
// If the model does exist then return the value of the field
|
||||
// or return 0 so the checkbox is unchecked.
|
||||
// Falling back to 0 here is because checkboxes are not sent
|
||||
// in the request when unchecked so they are not
|
||||
// actually saved in the model's options.
|
||||
return $this->options[$fieldName] ?? '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a radio field for the given field name.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string $value The value to check against.
|
||||
* @param bool $isDefault Whether the radio input being checked is the default.
|
||||
*
|
||||
*/
|
||||
public function radioValue(string $fieldName, string $value, bool $isDefault = false): bool
|
||||
{
|
||||
$fieldExists = array_has($this->options, $fieldName);
|
||||
|
||||
// If the field doesn't exist but the radio input
|
||||
// being checked is the default then return true.
|
||||
if (!$fieldExists && $isDefault) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the field exists and matches what we're checking then return true.
|
||||
if ($fieldExists && $this->options[$fieldName] === $value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a select field for the given field name.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string|null $model The Eloquent model to check against.
|
||||
*
|
||||
* @return mixed|null
|
||||
*
|
||||
*/
|
||||
public function selectValue(string $fieldName, string $model = null)
|
||||
{
|
||||
// If the field does not exist then return null.
|
||||
if (!isset($this->options[$fieldName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = $this->options[$fieldName];
|
||||
|
||||
// If the value was stored as an array, most likely
|
||||
// due to a previously being a multi-select,
|
||||
// then return the first value.
|
||||
if (is_array($value)) {
|
||||
$value = $value[0];
|
||||
}
|
||||
|
||||
// If a model is provided then we should ensure we only return
|
||||
// the value if the model still exists.
|
||||
// Note: It is possible $value is an id that no longer exists and this will return null.
|
||||
if ($model) {
|
||||
$foundModel = $model::find($value);
|
||||
|
||||
return $foundModel ? $foundModel->id : null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the values of a multi-select field for the given field name.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string|null $model The Eloquent model to check against.
|
||||
*
|
||||
* @return iterable
|
||||
*
|
||||
*/
|
||||
public function selectValues(string $fieldName, string $model = null): iterable
|
||||
{
|
||||
// If the field does not exist then return an empty array.
|
||||
if (!isset($this->options[$fieldName])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If a model is provided then we should ensure we only return
|
||||
// the ids of models that exist and are not deleted.
|
||||
if ($model) {
|
||||
return $model::findMany($this->options[$fieldName])->pluck('id');
|
||||
}
|
||||
|
||||
// Wrap the value in an array if needed. This is to ensure
|
||||
// values previously stored as a single value,
|
||||
// most likely from a single select, are returned as an array.
|
||||
if (!is_array($this->options[$fieldName])) {
|
||||
return [$this->options[$fieldName]];
|
||||
}
|
||||
|
||||
return $this->options[$fieldName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a text field for the given field name.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string|null $fallbackValue
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function textValue(string $fieldName, string|null $fallbackValue = ''): string
|
||||
{
|
||||
// Assuming we're using the null object pattern,
|
||||
// return the default value if the object is not saved yet.
|
||||
if (is_null($this->id)) {
|
||||
return (string) $fallbackValue;
|
||||
}
|
||||
|
||||
// Return the field's value if it exists
|
||||
// and return the default value if not.
|
||||
return $this->options[$fieldName] ?? '';
|
||||
}
|
||||
|
||||
public function getDisplayNameAttribute()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
+30
-31
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@@ -339,6 +340,33 @@ class Setting extends Model
|
||||
return collect($ldapSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a particular cache-file, refresh it if the settings have
|
||||
* been updated more recently than the file. Then return the
|
||||
* full filepath
|
||||
*/
|
||||
public static function get_fresh_file_path($attribute, $path)
|
||||
{
|
||||
$full_path = storage_path().'/'.$path;
|
||||
$file_exists = file_exists($full_path);
|
||||
if ($file_exists) {
|
||||
$statblock = stat($full_path);
|
||||
}
|
||||
if (!$file_exists || Carbon::createFromTimestamp($statblock['mtime']) < Setting::getSettings()->updated_at) {
|
||||
if (Setting::getSettings()->{$attribute}) {
|
||||
file_put_contents($full_path, Setting::getSettings()->{$attribute});
|
||||
} else {
|
||||
//this doesn't fire when you might expect it to because a lot of the time we do something like:
|
||||
// if ($settings->ldap_client_tls_cert && ...
|
||||
// so we never get a chance to 'uncache' the file.
|
||||
if ($file_exists) {
|
||||
unlink($full_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $full_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filename for the client-side SSL cert
|
||||
*
|
||||
@@ -346,7 +374,7 @@ class Setting extends Model
|
||||
*/
|
||||
public static function get_client_side_cert_path()
|
||||
{
|
||||
return storage_path().'/ldap_client_tls.cert';
|
||||
return self::get_fresh_file_path('ldap_client_tls_cert', 'ldap_client_tls.cert');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,36 +384,7 @@ class Setting extends Model
|
||||
*/
|
||||
public static function get_client_side_key_path()
|
||||
{
|
||||
return storage_path().'/ldap_client_tls.key';
|
||||
return self::get_fresh_file_path('ldap_client_tls_key', 'ldap_client_tls.key');
|
||||
}
|
||||
|
||||
public function update_client_side_cert_files()
|
||||
{
|
||||
/**
|
||||
* I'm not sure if it makes sense to have a cert but no key
|
||||
* nor vice versa, but for now I'm just leaving it like this.
|
||||
*
|
||||
* Also, we could easily set this up with an event handler and
|
||||
* self::saved() or something like that but there's literally only
|
||||
* one place where we will do that, so I'll just explicitly call
|
||||
* this method at that spot instead. It'll be easier to debug and understand.
|
||||
*/
|
||||
if ($this->ldap_client_tls_cert) {
|
||||
file_put_contents(self::get_client_side_cert_path(), $this->ldap_client_tls_cert);
|
||||
} else {
|
||||
if (file_exists(self::get_client_side_cert_path())) {
|
||||
unlink(self::get_client_side_cert_path());
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ldap_client_tls_key) {
|
||||
file_put_contents(self::get_client_side_key_path(), $this->ldap_client_tls_key);
|
||||
} else {
|
||||
if (file_exists(self::get_client_side_key_path())) {
|
||||
unlink(self::get_client_side_key_path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\Access\Authorizable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@@ -333,6 +334,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
public function accessories()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_checkout', 'assigned_to', 'accessory_id')
|
||||
->where('assigned_type', '=', 'App\Models\User')
|
||||
->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id');
|
||||
}
|
||||
|
||||
@@ -360,6 +362,15 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return $this->belongsToMany(\App\Models\License::class, 'license_seats', 'assigned_to', 'license_id')->withPivot('id', 'created_at', 'updated_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the user -> reportTemplates relationship
|
||||
*
|
||||
*/
|
||||
public function reportTemplates(): HasMany
|
||||
{
|
||||
return $this->hasMany(ReportTemplate::class, 'created_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a count of all items assigned
|
||||
*
|
||||
@@ -615,6 +626,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
$username = str_slug(substr($first_name, 0, 1).'.'.str_slug($last_name));
|
||||
} elseif ($format == 'lastname_firstinitial') {
|
||||
$username = str_slug($last_name).'_'.str_slug(substr($first_name, 0, 1));
|
||||
} elseif ($format == 'lastname.firstinitial') {
|
||||
$username = str_slug($last_name).'.'.str_slug(substr($first_name, 0, 1));
|
||||
} elseif ($format == 'firstnamelastname') {
|
||||
$username = str_slug($first_name).str_slug($last_name);
|
||||
} elseif ($format == 'firstnamelastinitial') {
|
||||
|
||||
@@ -79,7 +79,7 @@ class CheckinAssetNotification extends Notification
|
||||
|
||||
$fields = [
|
||||
trans('general.administrator') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>',
|
||||
trans('general.status') => $item->assetstatus->name,
|
||||
trans('general.status') => $item->assetstatus?->name,
|
||||
trans('general.location') => ($item->location) ? $item->location->name : '',
|
||||
];
|
||||
|
||||
@@ -106,9 +106,9 @@ class CheckinAssetNotification extends Notification
|
||||
->title(trans('mail.Asset_Checkin_Notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
|
||||
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
|
||||
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
|
||||
->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->present()->fullName())
|
||||
->fact(trans('admin/hardware/form.status'), $item->assetstatus->name)
|
||||
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@ class CheckinAssetNotification extends Notification
|
||||
$message = trans('mail.Asset_Checkin_Notification');
|
||||
$details = [
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
|
||||
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
|
||||
trans('mail.Asset_Checkin_Notification')." by " => $admin->present()->fullName(),
|
||||
trans('admin/hardware/form.status') => $item->assetstatus->name,
|
||||
trans('admin/hardware/form.status') => $item->assetstatus?->name,
|
||||
trans('mail.notes') => $note ?: '',
|
||||
];
|
||||
|
||||
@@ -142,8 +142,8 @@ class CheckinAssetNotification extends Notification
|
||||
Section::create(
|
||||
KeyValue::create(
|
||||
trans('mail.checked_into') ?: '',
|
||||
$item->location->name ? $item->location->name : '',
|
||||
trans('admin/hardware/form.status').": ".$item->assetstatus->name,
|
||||
($item->location) ? $item->location->name : '',
|
||||
trans('admin/hardware/form.status').": ".$item->assetstatus?->name,
|
||||
)
|
||||
->onClick(route('hardware.show', $item->id))
|
||||
)
|
||||
|
||||
@@ -48,7 +48,7 @@ class AssetObserver
|
||||
$changed = [];
|
||||
|
||||
foreach ($asset->getRawOriginal() as $key => $value) {
|
||||
if ($asset->getRawOriginal()[$key] != $asset->getAttributes()[$key]) {
|
||||
if ((array_key_exists($key, $asset->getAttributes())) && ($asset->getRawOriginal()[$key] != $asset->getAttributes()[$key])) {
|
||||
$changed[$key]['old'] = $asset->getRawOriginal()[$key];
|
||||
$changed[$key]['new'] = $asset->getAttributes()[$key];
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class AssetObserver
|
||||
{
|
||||
if ($settings = Setting::getSettings()) {
|
||||
$tag = $asset->asset_tag;
|
||||
$prefix = $settings->auto_increment_prefix;
|
||||
$prefix = (string)($settings->auto_increment_prefix ?? '');
|
||||
$number = substr($tag, strlen($prefix));
|
||||
// IF - auto_increment_assets is on, AND (there is no prefix OR the prefix matches the start of the tag)
|
||||
// AND the rest of the string after the prefix is all digits, THEN...
|
||||
|
||||
@@ -158,7 +158,7 @@ class AccessoryPresenter extends Presenter
|
||||
'title' => trans('general.change'),
|
||||
'formatter' => 'accessoriesInOutFormatter',
|
||||
], [
|
||||
'field' => 'actions',
|
||||
'field' => 'available_actions',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
@@ -170,6 +170,74 @@ class AccessoryPresenter extends Presenter
|
||||
return json_encode($layout);
|
||||
}
|
||||
|
||||
|
||||
public static function assignedDataTableLayout()
|
||||
{
|
||||
$layout = [
|
||||
[
|
||||
'field' => 'id',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.id'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'assigned_to.image',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.image'),
|
||||
'visible' => true,
|
||||
'formatter' => 'imageFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'assigned_to',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.checked_out_to'),
|
||||
'visible' => true,
|
||||
'formatter' => 'polymorphicItemFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'note',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.notes'),
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'field' => 'created_at',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/hardware/table.checkout_date'),
|
||||
'visible' => true,
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'created_by',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'title' => trans('general.admin'),
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'available_actions',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
'title' => trans('table.actions'),
|
||||
'formatter' => 'accessoriesInOutFormatter',
|
||||
],
|
||||
];
|
||||
|
||||
return json_encode($layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pregenerated link to this accessories view page.
|
||||
* @return string
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user