Compare commits
679 Commits
bulk_audit
...
use-transf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
943a4093ad | ||
|
|
b0917a5131 | ||
|
|
0972c4e340 | ||
|
|
43a237bf95 | ||
|
|
95f867b267 | ||
|
|
e96daf469a | ||
|
|
f2cdfe9e47 | ||
|
|
929b67e768 | ||
|
|
0573dc136a | ||
|
|
48588f6a9e | ||
|
|
88579b9bf3 | ||
|
|
e8bb9bde99 | ||
|
|
0ee3cca4da | ||
|
|
f89ee6b7f2 | ||
|
|
aebfb52c85 | ||
|
|
667bd7af0e | ||
|
|
bbf69bc582 | ||
|
|
f2b7a3d002 | ||
|
|
3fd9e3ab56 | ||
|
|
8e11466a54 | ||
|
|
dade9797d5 | ||
|
|
97c1e65ffc | ||
|
|
b4e22f4a21 | ||
|
|
58b6feb3ca | ||
|
|
41c4920d45 | ||
|
|
d1ddd8de98 | ||
|
|
f41307eb4a | ||
|
|
59de77feb0 | ||
|
|
8ebbcf6e80 | ||
|
|
24c6e836dd | ||
|
|
8e38b3898e | ||
|
|
ce9a5e35c9 | ||
|
|
b092779697 | ||
|
|
ab30a96d16 | ||
|
|
dab0fb16ad | ||
|
|
5be398bc99 | ||
|
|
fe4172957f | ||
|
|
ff3a59d347 | ||
|
|
f9aedea26f | ||
|
|
5abd2c7151 | ||
|
|
bfcaf4f37b | ||
|
|
5f4e1835bc | ||
|
|
c1f1ae6b64 | ||
|
|
c4fcc6c24e | ||
|
|
dd73ad9941 | ||
|
|
ac21f7569f | ||
|
|
4ef0158da4 | ||
|
|
4db3b3ba0e | ||
|
|
dc43d85323 | ||
|
|
62651f381c | ||
|
|
3e9098907a | ||
|
|
e18df250f8 | ||
|
|
be5c5a51da | ||
|
|
a728fad675 | ||
|
|
185629b310 | ||
|
|
30ebea4f2d | ||
|
|
b135c1eac2 | ||
|
|
88fef73d6f | ||
|
|
556a9039e9 | ||
|
|
cdfe6c21c1 | ||
|
|
b094ebdd66 | ||
|
|
526a7ddea6 | ||
|
|
bb5ad31cba | ||
|
|
549da2efed | ||
|
|
e5e586dc43 | ||
|
|
8a682beb0e | ||
|
|
699e9f75c9 | ||
|
|
759e30977b | ||
|
|
6cfdb49cc3 | ||
|
|
1195121bf0 | ||
|
|
8bc067b18b | ||
|
|
76f59f7b85 | ||
|
|
55ebb4671f | ||
|
|
8a9cf07063 | ||
|
|
ca9ff8cf19 | ||
|
|
7217d9c427 | ||
|
|
9d712ad8f1 | ||
|
|
f3e49e7010 | ||
|
|
ba94f1b920 | ||
|
|
edcd46dd67 | ||
|
|
5cf6c89dde | ||
|
|
58676b1f83 | ||
|
|
8ff7c30e5a | ||
|
|
cd989768d4 | ||
|
|
6cbdefe3d9 | ||
|
|
c6ecc0d8e8 | ||
|
|
e0f5663bf4 | ||
|
|
aafc8996c1 | ||
|
|
128da40cbf | ||
|
|
ea0460e97e | ||
|
|
d8e7123576 | ||
|
|
6f45ec655f | ||
|
|
ec17c168ea | ||
|
|
119b097521 | ||
|
|
c731633a84 | ||
|
|
6a4d6ade39 | ||
|
|
b3b4697fc9 | ||
|
|
72c706d697 | ||
|
|
8a7af24bd4 | ||
|
|
dd01bd3e5f | ||
|
|
59cade9f82 | ||
|
|
6bb9b79832 | ||
|
|
f8fe7b5803 | ||
|
|
4d6279d61c | ||
|
|
5ef581f328 | ||
|
|
20a59c343e | ||
|
|
d6feb522b7 | ||
|
|
951aee8292 | ||
|
|
6e2d7912b5 | ||
|
|
b20925b550 | ||
|
|
483f684b04 | ||
|
|
26774b4193 | ||
|
|
a7a597d609 | ||
|
|
1c12b9278a | ||
|
|
de4764bd05 | ||
|
|
c1e7a78d23 | ||
|
|
8894bb91cc | ||
|
|
c955126f01 | ||
|
|
ce53b48d04 | ||
|
|
6015aeddee | ||
|
|
7b04e30964 | ||
|
|
6794f5e783 | ||
|
|
6e41ceff39 | ||
|
|
7ab47ff0de | ||
|
|
92d24d8702 | ||
|
|
bcbfd46682 | ||
|
|
bfd96a695f | ||
|
|
f27e8534dc | ||
|
|
040cd7ddbf | ||
|
|
8d6b21a076 | ||
|
|
2d36b25017 | ||
|
|
1f9e4306ae | ||
|
|
5242e0b36e | ||
|
|
e50505532e | ||
|
|
f05ef18d55 | ||
|
|
f6eccd7277 | ||
|
|
4d1258c64b | ||
|
|
103cbfd038 | ||
|
|
47069ad3f4 | ||
|
|
317f620992 | ||
|
|
8f43694582 | ||
|
|
df30076ffd | ||
|
|
f81750617e | ||
|
|
e4534c4319 | ||
|
|
d6c09aae6b | ||
|
|
d3d5230d0c | ||
|
|
6f3c5c44a5 | ||
|
|
67b32ca14d | ||
|
|
bffaf477ea | ||
|
|
cba45ece12 | ||
|
|
3290d7f401 | ||
|
|
ef3827376d | ||
|
|
4ae8a91051 | ||
|
|
ff4819ac68 | ||
|
|
58af133853 | ||
|
|
8199cd2118 | ||
|
|
9f02b80cf1 | ||
|
|
d3e4e81168 | ||
|
|
38195c0a8f | ||
|
|
5fa11e4278 | ||
|
|
c39b52fcb5 | ||
|
|
ec65fc1e65 | ||
|
|
32d8646d96 | ||
|
|
e8835fc2b1 | ||
|
|
054a06c5dc | ||
|
|
9c61d2eb22 | ||
|
|
d66b6cfee6 | ||
|
|
89c0427b2f | ||
|
|
3fec10d447 | ||
|
|
f8b4981bfe | ||
|
|
130669a2f9 | ||
|
|
c2c79ee231 | ||
|
|
86f10bd702 | ||
|
|
b496a06fc0 | ||
|
|
f865a6cb37 | ||
|
|
89186ea4f8 | ||
|
|
fb19985186 | ||
|
|
ebc6e1221a | ||
|
|
2b91dcb700 | ||
|
|
9d2e333fd6 | ||
|
|
013ad1069c | ||
|
|
ec059717f6 | ||
|
|
418566db3f | ||
|
|
7be9463be6 | ||
|
|
51712bc7d6 | ||
|
|
7b889d22d2 | ||
|
|
e8aad989ec | ||
|
|
4006d64d60 | ||
|
|
d792d99375 | ||
|
|
b11036a2e5 | ||
|
|
01de69a250 | ||
|
|
5e1c2e7feb | ||
|
|
b842aa11e5 | ||
|
|
ff01078b60 | ||
|
|
b1e92293fc | ||
|
|
443f69bd82 | ||
|
|
f4decbf52e | ||
|
|
bd2c311e4f | ||
|
|
2dcab6d0b3 | ||
|
|
c68a97198f | ||
|
|
2702c3da2b | ||
|
|
da06e9afd5 | ||
|
|
1623f13539 | ||
|
|
5910982a4f | ||
|
|
74630b36b0 | ||
|
|
ace4a5d614 | ||
|
|
0d41947f64 | ||
|
|
78de3b3591 | ||
|
|
0a4a6e7ba3 | ||
|
|
090399b336 | ||
|
|
47afb15970 | ||
|
|
b1ba3376aa | ||
|
|
8c1e19e77c | ||
|
|
0801d1473c | ||
|
|
6d98878c72 | ||
|
|
2d404fdadc | ||
|
|
b264fde165 | ||
|
|
970ff25e5e | ||
|
|
9dd3eee65c | ||
|
|
957faa6651 | ||
|
|
cc7dcc6e81 | ||
|
|
f666cba104 | ||
|
|
7f35498919 | ||
|
|
297205ff91 | ||
|
|
6f99381d13 | ||
|
|
45a42b00ad | ||
|
|
6586858284 | ||
|
|
19cce15e54 | ||
|
|
62b8e4c46f | ||
|
|
74b7d27408 | ||
|
|
a60ffc0702 | ||
|
|
9b8524ba27 | ||
|
|
32526d77b8 | ||
|
|
ba7db8f7b3 | ||
|
|
04712ad252 | ||
|
|
5711a9e148 | ||
|
|
a0f40c2dfb | ||
|
|
34636016eb | ||
|
|
95027e329c | ||
|
|
c9778a73c7 | ||
|
|
628d2a0a0a | ||
|
|
cc0ff1ec1f | ||
|
|
6543540509 | ||
|
|
cd53fc6318 | ||
|
|
4934b6c4da | ||
|
|
59db38524b | ||
|
|
3f5cfc3a4b | ||
|
|
3443f02c0a | ||
|
|
9a012ca01e | ||
|
|
509ef34cca | ||
|
|
49c289a094 | ||
|
|
10e5d88fb6 | ||
|
|
ae64fb3fdb | ||
|
|
cac2fde504 | ||
|
|
bb38a96fd1 | ||
|
|
79dbcb10c9 | ||
|
|
7c80fdea58 | ||
|
|
5500a42744 | ||
|
|
ae46264707 | ||
|
|
f2d8665e54 | ||
|
|
db7110d6b2 | ||
|
|
4e06b597fe | ||
|
|
fe006d05d3 | ||
|
|
358b70e280 | ||
|
|
a060dde625 | ||
|
|
3cfed72af4 | ||
|
|
4c59989236 | ||
|
|
6c1adff5c8 | ||
|
|
9293bdca06 | ||
|
|
beeccbfb44 | ||
|
|
0d3d2e2e78 | ||
|
|
2af7605451 | ||
|
|
976cc1c86f | ||
|
|
cbbf3aa6c8 | ||
|
|
4f8ff98d5b | ||
|
|
d4fe81c290 | ||
|
|
cbdf03aa66 | ||
|
|
d756670c56 | ||
|
|
9ef7b0e64a | ||
|
|
2d7c0f7e5f | ||
|
|
ec8ddc197f | ||
|
|
b48e56bd46 | ||
|
|
753ca93371 | ||
|
|
04f71e7f6a | ||
|
|
5d129dd420 | ||
|
|
1c37c630aa | ||
|
|
d329d6104e | ||
|
|
482723f3bc | ||
|
|
cbc025b1ff | ||
|
|
bf8ceceabe | ||
|
|
fba4bba132 | ||
|
|
0ded40c037 | ||
|
|
6f486a37ff | ||
|
|
1ef822997b | ||
|
|
ea66629e98 | ||
|
|
84c9979fe3 | ||
|
|
867a992183 | ||
|
|
c3ad7d649c | ||
|
|
fc250e228d | ||
|
|
37e81568ea | ||
|
|
048d910d5b | ||
|
|
b162aba445 | ||
|
|
974627849b | ||
|
|
e18e9f699e | ||
|
|
cc9209d2de | ||
|
|
dd3d264e63 | ||
|
|
246f1373a8 | ||
|
|
b993f4270e | ||
|
|
6c51ef11b1 | ||
|
|
ae98f6276e | ||
|
|
7424a5987b | ||
|
|
2d08749207 | ||
|
|
db50e98ae3 | ||
|
|
7ec0925c69 | ||
|
|
df1361aa43 | ||
|
|
6db04c86df | ||
|
|
bec80b443c | ||
|
|
333501fe55 | ||
|
|
063553d4f7 | ||
|
|
19b9e50281 | ||
|
|
2a68b4aeff | ||
|
|
5e25150521 | ||
|
|
cb183d3645 | ||
|
|
96bce301a0 | ||
|
|
360f5b7538 | ||
|
|
77234f6580 | ||
|
|
088e6af0b5 | ||
|
|
16fb1018a2 | ||
|
|
e2e54677ee | ||
|
|
ad6fe855a9 | ||
|
|
c50c97d149 | ||
|
|
8b98ae15f0 | ||
|
|
261f84d5f5 | ||
|
|
29989ac24e | ||
|
|
7a93e94fa6 | ||
|
|
e33f73fe9f | ||
|
|
6291389df5 | ||
|
|
ed817dc414 | ||
|
|
7494fa6bc9 | ||
|
|
62e50dbe52 | ||
|
|
30c090ba2d | ||
|
|
7ff82e6043 | ||
|
|
2950fb1041 | ||
|
|
61d3e2fb49 | ||
|
|
fb18c1a0be | ||
|
|
68c082e0dc | ||
|
|
ee3deb9c63 | ||
|
|
c1505de8d6 | ||
|
|
10be434c13 | ||
|
|
92e22eead5 | ||
|
|
31db86abd3 | ||
|
|
8e70ff135a | ||
|
|
5ec52f7471 | ||
|
|
8bc57f98a5 | ||
|
|
6f4cee6334 | ||
|
|
6beccc5e60 | ||
|
|
fed8e10644 | ||
|
|
3c0121c1d0 | ||
|
|
02021e3fb9 | ||
|
|
ea447365fa | ||
|
|
60989d6766 | ||
|
|
a2960dc653 | ||
|
|
702499dd79 | ||
|
|
482c427e34 | ||
|
|
67910490bd | ||
|
|
fdb5ab2293 | ||
|
|
092d9d1e42 | ||
|
|
e657f11531 | ||
|
|
9aac183318 | ||
|
|
c8c2867305 | ||
|
|
3e1f71026c | ||
|
|
dc562d8c20 | ||
|
|
84ec5aea26 | ||
|
|
444c13c6ea | ||
|
|
12d5e4f7d2 | ||
|
|
0fb1639915 | ||
|
|
d01f7cf317 | ||
|
|
03725c8e0c | ||
|
|
3942489d21 | ||
|
|
51479c8bbc | ||
|
|
ea3364ab68 | ||
|
|
cb608d7fd1 | ||
|
|
7129008428 | ||
|
|
3b832f507f | ||
|
|
b5849500f9 | ||
|
|
9eaabf95a0 | ||
|
|
724f38abc2 | ||
|
|
0dfc083a91 | ||
|
|
16432f503a | ||
|
|
7c9433be5d | ||
|
|
e4ce71ff14 | ||
|
|
45c6406ff4 | ||
|
|
550e2b6bb8 | ||
|
|
a7bb890729 | ||
|
|
3d8f8faf01 | ||
|
|
55cf5877c4 | ||
|
|
dec3c4aff3 | ||
|
|
79e00c1191 | ||
|
|
12dc33244d | ||
|
|
6e37f945ac | ||
|
|
d75120000a | ||
|
|
9e4aab7165 | ||
|
|
6bc3209333 | ||
|
|
054ff42547 | ||
|
|
11b47b308b | ||
|
|
367ab8ddd5 | ||
|
|
4f5d4a0984 | ||
|
|
40489c53d6 | ||
|
|
93b760d53b | ||
|
|
e86996bc7e | ||
|
|
14244f45b6 | ||
|
|
1b9d90a322 | ||
|
|
736f74d083 | ||
|
|
8194c6efdb | ||
|
|
aae2a17ad1 | ||
|
|
f44150668c | ||
|
|
6eed2deb09 | ||
|
|
878c6e7031 | ||
|
|
1f4a73fab6 | ||
|
|
7a315523fe | ||
|
|
6f082e662b | ||
|
|
018c981c5a | ||
|
|
0149773a03 | ||
|
|
5d46d90725 | ||
|
|
0544e05f32 | ||
|
|
80ff42a41f | ||
|
|
90b7df45b9 | ||
|
|
32858b973a | ||
|
|
40ba8d0de1 | ||
|
|
8ddbb4e64f | ||
|
|
cc40c48aac | ||
|
|
522ab9e0f5 | ||
|
|
97187aa7eb | ||
|
|
d93a5aa623 | ||
|
|
a5b88982bf | ||
|
|
df71bdcada | ||
|
|
51bab2dd26 | ||
|
|
ed8da6ad1b | ||
|
|
18d0a04efc | ||
|
|
bb68ed3ad9 | ||
|
|
402ca07aa2 | ||
|
|
28dc358df1 | ||
|
|
3cf1e9d55d | ||
|
|
82b001ab5f | ||
|
|
7b272226ce | ||
|
|
78d26fb7f6 | ||
|
|
930842e685 | ||
|
|
b938cb42d8 | ||
|
|
4c7b6d130f | ||
|
|
af57ca4983 | ||
|
|
40c31a1ad7 | ||
|
|
7ae4a4177f | ||
|
|
6efd323fbf | ||
|
|
ed9dbcc777 | ||
|
|
c2cf7de41b | ||
|
|
32bd14bd2d | ||
|
|
f9cbecdb17 | ||
|
|
7bb29a0277 | ||
|
|
d5f7579e9f | ||
|
|
13fd43c45c | ||
|
|
c08ce901cc | ||
|
|
94bd11d3c9 | ||
|
|
59c6e26b29 | ||
|
|
bf7cc404f8 | ||
|
|
12a2c71b90 | ||
|
|
6e2eeba0f6 | ||
|
|
99a739fae3 | ||
|
|
0185f61c11 | ||
|
|
783f0c113d | ||
|
|
75a839cc21 | ||
|
|
577b5586b4 | ||
|
|
1474a16148 | ||
|
|
9baa2000e1 | ||
|
|
d0624dbefe | ||
|
|
ecb6e8d9a9 | ||
|
|
bbb299faf2 | ||
|
|
ba3b55cab0 | ||
|
|
67acca7bc8 | ||
|
|
e4b33c3b56 | ||
|
|
ed43c73cec | ||
|
|
a6fa795b41 | ||
|
|
3a6bac2e63 | ||
|
|
8e01c05e42 | ||
|
|
fabf9281e9 | ||
|
|
6588d409b8 | ||
|
|
92a3421a4e | ||
|
|
a42147ff34 | ||
|
|
0df1bc6894 | ||
|
|
9317076c5e | ||
|
|
1b5525c51f | ||
|
|
6019c80c7b | ||
|
|
aaa6cb24d4 | ||
|
|
1ef5ad500a | ||
|
|
9468acedfa | ||
|
|
6a951b6357 | ||
|
|
95f7742259 | ||
|
|
9f795306e5 | ||
|
|
6feaff1e7b | ||
|
|
9a168354ae | ||
|
|
309d242c4d | ||
|
|
5c174f829e | ||
|
|
3c428f2d7b | ||
|
|
6833716576 | ||
|
|
bd374d031a | ||
|
|
ef26f48f60 | ||
|
|
b07f8525db | ||
|
|
9f062701fa | ||
|
|
2c452daddf | ||
|
|
53a82d3f4d | ||
|
|
b5b8816279 | ||
|
|
7bc4127e8c | ||
|
|
06158cc413 | ||
|
|
cb49e7c9a6 | ||
|
|
1822027a8f | ||
|
|
c8dabc25e3 | ||
|
|
f2b10eeee8 | ||
|
|
4b52e1471c | ||
|
|
f6bba03375 | ||
|
|
b3813a7121 | ||
|
|
eb2a1396ca | ||
|
|
0fae18c4ba | ||
|
|
25ac83e944 | ||
|
|
a82e65e190 | ||
|
|
187bb90de0 | ||
|
|
293648582a | ||
|
|
51a306993c | ||
|
|
ec1851fa84 | ||
|
|
bbe748dbd3 | ||
|
|
406e8c5874 | ||
|
|
a4f71a9f0a | ||
|
|
3748498523 | ||
|
|
49d11103f7 | ||
|
|
dce9060820 | ||
|
|
de6206ce78 | ||
|
|
a181ba308a | ||
|
|
5a9ac01cf8 | ||
|
|
a5cd306b1d | ||
|
|
57d3abab5f | ||
|
|
b6eb3185d5 | ||
|
|
286f78778c | ||
|
|
4b95790e2f | ||
|
|
97883971f7 | ||
|
|
b3c12d4ee6 | ||
|
|
bea426d8e6 | ||
|
|
be60370eae | ||
|
|
7cc216eb38 | ||
|
|
8c90efe745 | ||
|
|
4b9f4423f6 | ||
|
|
932b589bd9 | ||
|
|
ce18b91b03 | ||
|
|
5f883310b5 | ||
|
|
69cc46c2b8 | ||
|
|
dc6951f341 | ||
|
|
f7ed336f99 | ||
|
|
47f287c031 | ||
|
|
5739393f8d | ||
|
|
13956254ce | ||
|
|
d6b69c8cc2 | ||
|
|
7a79fd18f0 | ||
|
|
e3ffe79c4c | ||
|
|
043325b966 | ||
|
|
a2696b799f | ||
|
|
eb8ef37808 | ||
|
|
8416c6df05 | ||
|
|
3aa4814342 | ||
|
|
186f322bb5 | ||
|
|
28e2e7c924 | ||
|
|
97351028b5 | ||
|
|
0ef0863b59 | ||
|
|
2e80b4ace8 | ||
|
|
0d896c2ef6 | ||
|
|
dc9df04237 | ||
|
|
b469a64db3 | ||
|
|
73f19ff4e7 | ||
|
|
22b4fac3ee | ||
|
|
c97884c8b0 | ||
|
|
b972fb514a | ||
|
|
a3871bd1f2 | ||
|
|
2069f99b2b | ||
|
|
882d55fd09 | ||
|
|
68ef975726 | ||
|
|
0685ff3818 | ||
|
|
b28839d907 | ||
|
|
7f0a947de4 | ||
|
|
c8fc4afe65 | ||
|
|
3b7162cb02 | ||
|
|
4245456382 | ||
|
|
cdf43e31e2 | ||
|
|
f19d6b3c52 | ||
|
|
ca66e29072 | ||
|
|
6ff76a12f8 | ||
|
|
8b13997597 | ||
|
|
9600adee6b | ||
|
|
6eb3819492 | ||
|
|
95226f87bc | ||
|
|
ee3ae803b9 | ||
|
|
057667c425 | ||
|
|
02fa7daa1d | ||
|
|
2a2acf6d1c | ||
|
|
f644642fac | ||
|
|
3374a9e5a9 | ||
|
|
d3a74a5740 | ||
|
|
c458cc904a | ||
|
|
5c7b74e17e | ||
|
|
e07b0f65a1 | ||
|
|
b06fd5bbca | ||
|
|
6306f78fe0 | ||
|
|
da4bce0c89 | ||
|
|
053e815206 | ||
|
|
ab1053ecda | ||
|
|
9a61a3391b | ||
|
|
d3c19e28ec | ||
|
|
87115f2e50 | ||
|
|
5f7aadfba0 | ||
|
|
e954e066b4 | ||
|
|
e336182d79 | ||
|
|
3eb0743446 | ||
|
|
95c1c37ab1 | ||
|
|
a7054f0b1e | ||
|
|
e4bfabfabe | ||
|
|
6b56929a06 | ||
|
|
e3642bb513 | ||
|
|
ca7c416e19 | ||
|
|
ac6d964e28 | ||
|
|
e2772c816d | ||
|
|
916f7401f3 | ||
|
|
b53a71d523 | ||
|
|
510a2b0889 | ||
|
|
73057454c6 | ||
|
|
5a6cf2a296 | ||
|
|
9e3e04521e | ||
|
|
65dfbd02fe | ||
|
|
649ab53320 | ||
|
|
9250624f79 | ||
|
|
995e2090f5 | ||
|
|
9b91584776 | ||
|
|
8fd97ea501 | ||
|
|
a80b9ab362 | ||
|
|
556e1081b3 | ||
|
|
b070916f0b | ||
|
|
940caf14b0 | ||
|
|
76da1d6663 | ||
|
|
bafff9020a | ||
|
|
0d5dca6456 | ||
|
|
0f9b7119c0 | ||
|
|
d4181549e8 | ||
|
|
d57f56e44f | ||
|
|
f7777ca8a5 | ||
|
|
fce5530bc7 | ||
|
|
ad1530e9ff | ||
|
|
abb2dcbbe4 | ||
|
|
437499c5df | ||
|
|
f739c2c84a | ||
|
|
248a05a916 | ||
|
|
2c141579dd | ||
|
|
e3a2397b74 | ||
|
|
3b34654dd7 | ||
|
|
4b6437854c | ||
|
|
c385b4a082 | ||
|
|
1b961346f0 | ||
|
|
100db23210 | ||
|
|
3e980a4c57 | ||
|
|
9a3ac41370 | ||
|
|
4ef161214d | ||
|
|
29d0380db3 | ||
|
|
0b48fd1465 | ||
|
|
220537fbfb | ||
|
|
df5437647b | ||
|
|
92b2da9b1b | ||
|
|
ef56177372 | ||
|
|
cb7822576f | ||
|
|
7ba361b10d | ||
|
|
55694fa2fc | ||
|
|
c825878c46 | ||
|
|
80a69bfe90 | ||
|
|
d4dc8d2b79 | ||
|
|
4e3df93349 | ||
|
|
38efc62900 | ||
|
|
a2ff8f9609 |
@@ -4153,6 +4153,42 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "JassonCordones",
|
||||||
|
"name": "Jasson",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/4875039?v=4",
|
||||||
|
"profile": "http://jassoncordones.github.io",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Tinyblargon",
|
||||||
|
"name": "Okean",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/76069640?v=4",
|
||||||
|
"profile": "https://github.com/Tinyblargon",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "amedranogil",
|
||||||
|
"name": "Alejandro Medrano",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/6515064?v=4",
|
||||||
|
"profile": "https://www.lst.tfo.upm.es/alejandro-medrano/",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "lukaskraic",
|
||||||
|
"name": "Lukas Kraic",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/58696401?v=4",
|
||||||
|
"profile": "https://github.com/lukaskraic",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4
.github/workflows/codacy-analysis.yml
vendored
4
.github/workflows/codacy-analysis.yml
vendored
@@ -10,10 +10,10 @@ name: Codacy Security Scan
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ develop ]
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ master ]
|
branches: [ develop ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '36 23 * * 3'
|
- cron: '36 23 * * 3'
|
||||||
|
|
||||||
|
|||||||
667
CONTRIBUTORS.md
667
CONTRIBUTORS.md
@@ -1,606 +1,73 @@
|
|||||||
Thanks goes to all of these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)) who have helped Snipe-IT get this far:
|
Thanks goes to all of these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)) who have helped Snipe-IT get this far:
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
<!-- prettier-ignore-start -->
|
| [<img src="https://avatars3.githubusercontent.com/u/197404?v=3" width="110px;"/><br /><sub>snipe</sub>](http://www.snipe.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=snipe "Code") [🚇](#infra-snipe "Infrastructure (Hosting, Build-Tools, etc)") [📖](https://github.com/snipe/snipe-it/commits?author=snipe "Documentation") [⚠️](https://github.com/snipe/snipe-it/commits?author=snipe "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Asnipe "Bug reports") [🎨](#design-snipe "Design") [👀](#review-snipe "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/36335?v=3" width="110px;"/><br /><sub>Brady Wetherington</sub>](http://www.uberbrady.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=uberbrady "Code") [📖](https://github.com/snipe/snipe-it/commits?author=uberbrady "Documentation") [🚇](#infra-uberbrady "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-uberbrady "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/3803132?v=3" width="110px;"/><br /><sub>Daniel Meltzer</sub>](https://github.com/dmeltzer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Tests") [📖](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/1609106?v=3" width="110px;"/><br /><sub>Michael T</sub>](http://www.tuckertechonline.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mtucker6784 "Code") | [<img src="https://avatars2.githubusercontent.com/u/3274937?v=3" width="110px;"/><br /><sub>madd15</sub>](https://github.com/madd15)<br />[📖](https://github.com/snipe/snipe-it/commits?author=madd15 "Documentation") [💬](#question-madd15 "Answering Questions") | [<img src="https://avatars2.githubusercontent.com/u/894126?v=3" width="110px;"/><br /><sub>Vincent Sposato</sub>](https://github.com/vsposato)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vsposato "Code") | [<img src="https://avatars0.githubusercontent.com/u/1639757?v=3" width="110px;"/><br /><sub>Andrea Bergamasco</sub>](https://github.com/vjandrea)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vjandrea "Code") |
|
||||||
<!-- markdownlint-disable -->
|
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||||
<table>
|
| [<img src="https://avatars0.githubusercontent.com/u/10640152?v=3" width="110px;"/><br /><sub>Karol</sub>](https://github.com/kpawelski)<br />[🌍](#translation-kpawelski "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=kpawelski "Code") | [<img src="https://avatars3.githubusercontent.com/u/600106?v=3" width="110px;"/><br /><sub>morph027</sub>](http://blog.morph027.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=morph027 "Code") | [<img src="https://avatars3.githubusercontent.com/u/22935755?v=3" width="110px;"/><br /><sub>fvleminckx</sub>](https://github.com/fvleminckx)<br />[🚇](#infra-fvleminckx "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars2.githubusercontent.com/u/15633547?v=3" width="110px;"/><br /><sub>itsupportcmsukorg</sub>](https://github.com/itsupportcmsukorg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=itsupportcmsukorg "Code") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aitsupportcmsukorg "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/12373799?v=3" width="110px;"/><br /><sub>Frank</sub>](https://override.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=base-zero "Code") | [<img src="https://avatars0.githubusercontent.com/u/10137?v=3" width="110px;"/><br /><sub>Deleted user</sub>](https://github.com/ghost)<br />[🌍](#translation-ghost "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=ghost "Code") | [<img src="https://avatars1.githubusercontent.com/u/10802313?v=3" width="110px;"/><br /><sub>tiagom62</sub>](https://github.com/tiagom62)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tiagom62 "Code") [🚇](#infra-tiagom62 "Infrastructure (Hosting, Build-Tools, etc)") |
|
||||||
<tbody>
|
| [<img src="https://avatars3.githubusercontent.com/u/2389047?v=3" width="110px;"/><br /><sub>Ryan Stafford</sub>](https://github.com/rystaf)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rystaf "Code") | [<img src="https://avatars2.githubusercontent.com/u/10345935?v=3" width="110px;"/><br /><sub>Eammon Hanlon</sub>](https://github.com/ehanlon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ehanlon "Code") | [<img src="https://avatars0.githubusercontent.com/u/441924?v=3" width="110px;"/><br /><sub>zjean</sub>](https://github.com/zjean)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zjean "Code") | [<img src="https://avatars0.githubusercontent.com/u/12660103?v=3" width="110px;"/><br /><sub>Matthias Frei</sub>](http://www.frei.media)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FREImedia "Code") | [<img src="https://avatars0.githubusercontent.com/u/3767518?v=3" width="110px;"/><br /><sub>opsydev</sub>](https://github.com/opsydev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=opsydev "Code") | [<img src="https://avatars1.githubusercontent.com/u/82290?v=3" width="110px;"/><br /><sub>Daniel Dreier</sub>](http://www.ddreier.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ddreier "Code") | [<img src="https://avatars0.githubusercontent.com/u/23448?v=3" width="110px;"/><br /><sub>Nikolai Prokoschenko</sub>](http://rassie.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rassie "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars0.githubusercontent.com/u/13452757?v=3" width="110px;"/><br /><sub>Drew</sub>](https://github.com/YetAnotherCodeMonkey)<br />[💻](https://github.com/snipe/snipe-it/commits?author=YetAnotherCodeMonkey "Code") | [<img src="https://avatars0.githubusercontent.com/u/1342320?v=3" width="110px;"/><br /><sub>Walter</sub>](https://github.com/merid14)<br />[💻](https://github.com/snipe/snipe-it/commits?author=merid14 "Code") | [<img src="https://avatars3.githubusercontent.com/u/11254614?v=3" width="110px;"/><br /><sub>Petr Baloun</sub>](https://github.com/balous)<br />[💻](https://github.com/snipe/snipe-it/commits?author=balous "Code") | [<img src="https://avatars0.githubusercontent.com/u/6117660?v=3" width="110px;"/><br /><sub>reidblomquist</sub>](https://github.com/reidblomquist)<br />[📖](https://github.com/snipe/snipe-it/commits?author=reidblomquist "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/539914?v=3" width="110px;"/><br /><sub>Mathieu Kooiman</sub>](https://github.com/mathieuk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mathieuk "Code") | [<img src="https://avatars3.githubusercontent.com/u/6606421?v=3" width="110px;"/><br /><sub>csayre</sub>](https://github.com/csayre)<br />[📖](https://github.com/snipe/snipe-it/commits?author=csayre "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/768488?v=3" width="110px;"/><br /><sub>Adam Dunson</sub>](https://github.com/adamdunson)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamdunson "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.snipe.net"><img src="https://avatars3.githubusercontent.com/u/197404?v=3?s=110" width="110px;" alt="snipe"/><br /><sub><b>snipe</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Code">💻</a> <a href="#infra-snipe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Documentation">📖</a> <a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3Asnipe" title="Bug reports">🐛</a> <a href="#design-snipe" title="Design">🎨</a> <a href="https://github.com/snipe/snipe-it/pulls?q=is%3Apr+reviewed-by%3Asnipe" title="Reviewed Pull Requests">👀</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/5547470?v=3" width="110px;"/><br /><sub>Hereward</sub>](https://github.com/thehereward)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thehereward "Code") | [<img src="https://avatars0.githubusercontent.com/u/5802977?v=3" width="110px;"/><br /><sub>swoopdk</sub>](https://github.com/swoopdk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=swoopdk "Code") | [<img src="https://avatars1.githubusercontent.com/u/3470403?v=3" width="110px;"/><br /><sub>Abdullah Alansari</sub>](https://linkedin.com/in/ahimta)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Ahimta "Code") | [<img src="https://avatars0.githubusercontent.com/u/796443?v=3" width="110px;"/><br /><sub>Micael Rodrigues</sub>](https://github.com/MicaelRodrigues)<br />[💻](https://github.com/snipe/snipe-it/commits?author=MicaelRodrigues "Code") | [<img src="https://avatars0.githubusercontent.com/u/614564?v=3" width="110px;"/><br /><sub>Patrick Gallagher</sub>](http://macadmincorner.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=patgmac "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/7165922?v=3" width="110px;"/><br /><sub>Miliamber</sub>](https://github.com/Miliamber)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Miliamber "Code") | [<img src="https://avatars3.githubusercontent.com/u/861766?v=3" width="110px;"/><br /><sub>hawk554</sub>](https://github.com/hawk554)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hawk554 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.uberbrady.com"><img src="https://avatars0.githubusercontent.com/u/36335?v=3?s=110" width="110px;" alt="Brady Wetherington"/><br /><sub><b>Brady Wetherington</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=uberbrady" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=uberbrady" title="Documentation">📖</a> <a href="#infra-uberbrady" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/snipe/snipe-it/pulls?q=is%3Apr+reviewed-by%3Auberbrady" title="Reviewed Pull Requests">👀</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/1695622?v=3" width="110px;"/><br /><sub>Justin Kerr</sub>](http://jbirdkerr.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jbirdkerr "Code") | [<img src="https://avatars3.githubusercontent.com/u/11426176?v=3" width="110px;"/><br /><sub>Ira W. Snyder</sub>](http://www.irasnyder.com/devel/)<br />[📖](https://github.com/snipe/snipe-it/commits?author=irasnyd "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/2475759?v=3" width="110px;"/><br /><sub>Aladin Alaily</sub>](https://github.com/aalaily)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aalaily "Code") | [<img src="https://avatars0.githubusercontent.com/u/10247644?v=3" width="110px;"/><br /><sub>Chase Hansen</sub>](https://github.com/kobie-chasehansen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kobie-chasehansen "Code") [💬](#question-kobie-chasehansen "Answering Questions") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Akobie-chasehansen "Bug reports") | [<img src="https://avatars2.githubusercontent.com/u/13545400?v=3" width="110px;"/><br /><sub>IDM Helpdesk</sub>](https://github.com/IDM-Helpdesk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=IDM-Helpdesk "Code") | [<img src="https://avatars2.githubusercontent.com/u/614439?v=3" width="110px;"/><br /><sub>Kai</sub>](http://balticer.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=balticer "Code") | [<img src="https://avatars1.githubusercontent.com/u/8762511?v=3" width="110px;"/><br /><sub>Michael Daniels</sub>](http://www.michaeldaniels.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mdaniels5757 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dmeltzer"><img src="https://avatars0.githubusercontent.com/u/3803132?v=3?s=110" width="110px;" alt="Daniel Meltzer"/><br /><sub><b>Daniel Meltzer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Documentation">📖</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/1532660?v=3" width="110px;"/><br /><sub>Tom Castleman</sub>](http://tomcastleman.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tomcastleman "Code") | [<img src="https://avatars3.githubusercontent.com/u/10723243?v=3" width="110px;"/><br /><sub>Daniel Nemanic</sub>](https://github.com/DanielNemanic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DanielNemanic "Code") | [<img src="https://avatars0.githubusercontent.com/u/150648?v=3" width="110px;"/><br /><sub>SouthWolf</sub>](https://github.com/southwolf)<br />[💻](https://github.com/snipe/snipe-it/commits?author=southwolf "Code") | [<img src="https://avatars2.githubusercontent.com/u/131616?v=3" width="110px;"/><br /><sub>Ivar Nesje</sub>](https://github.com/ivarne)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ivarne "Code") | [<img src="https://avatars1.githubusercontent.com/u/62333?v=3" width="110px;"/><br /><sub>Jérémy Benoist</sub>](http://www.j0k3r.net)<br />[📖](https://github.com/snipe/snipe-it/commits?author=j0k3r "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/724344?v=3" width="110px;"/><br /><sub>Chris Leathley</sub>](https://github.com/cleathley)<br />[🚇](#infra-cleathley "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars0.githubusercontent.com/u/972498?v=3" width="110px;"/><br /><sub>splaer</sub>](https://github.com/splaer)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Asplaer "Bug reports") [💻](https://github.com/snipe/snipe-it/commits?author=splaer "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.tuckertechonline.com"><img src="https://avatars0.githubusercontent.com/u/1609106?v=3?s=110" width="110px;" alt="Michael T"/><br /><sub><b>Michael T</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mtucker6784" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/967362?v=3" width="110px;"/><br /><sub>Joe Ferguson</sub>](http://www.joeferguson.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=svpernova09 "Code") | [<img src="https://avatars3.githubusercontent.com/u/6108682?v=3" width="110px;"/><br /><sub>diwanicki</sub>](https://github.com/diwanicki)<br />[💻](https://github.com/snipe/snipe-it/commits?author=diwanicki "Code") [📖](https://github.com/snipe/snipe-it/commits?author=diwanicki "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/2527115?v=3" width="110px;"/><br /><sub>Lee Thoong Ching</sub>](https://github.com/pakkua80)<br />[📖](https://github.com/snipe/snipe-it/commits?author=pakkua80 "Documentation") [💻](https://github.com/snipe/snipe-it/commits?author=pakkua80 "Code") | [<img src="https://avatars1.githubusercontent.com/u/461491?v=3" width="110px;"/><br /><sub>Marek Šuppa</sub>](http://shu.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrshu "Code") | [<img src="https://avatars1.githubusercontent.com/u/8693762?v=3" width="110px;"/><br /><sub>Juan J. Martinez</sub>](https://github.com/mizar1616)<br />[🌍](#translation-mizar1616 "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1458388?v=3" width="110px;"/><br /><sub>R Ryan Dial</sub>](https://github.com/rrdial)<br />[🌍](#translation-rrdial "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2871745?v=3" width="110px;"/><br /><sub>Andrej Manduch</sub>](https://github.com/burlito)<br />[📖](https://github.com/snipe/snipe-it/commits?author=burlito "Documentation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/madd15"><img src="https://avatars2.githubusercontent.com/u/3274937?v=3?s=110" width="110px;" alt="madd15"/><br /><sub><b>madd15</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=madd15" title="Documentation">📖</a> <a href="#question-madd15" title="Answering Questions">💬</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/8341172?v=3" width="110px;"/><br /><sub>Jay Richards</sub>](http://www.cordeos.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=technogenus "Code") | [<img src="https://avatars2.githubusercontent.com/u/7295127?v=3" width="110px;"/><br /><sub>Alexander Innes</sub>](https://necurity.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leostat "Code") | [<img src="https://avatars2.githubusercontent.com/u/334485?v=3" width="110px;"/><br /><sub>Danny Garcia</sub>](https://buzzedword.codes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=buzzedword "Code") | [<img src="https://avatars2.githubusercontent.com/u/366855?v=3" width="110px;"/><br /><sub>archpoint</sub>](https://github.com/archpoint)<br />[💻](https://github.com/snipe/snipe-it/commits?author=archpoint "Code") | [<img src="https://avatars1.githubusercontent.com/u/67991?v=3" width="110px;"/><br /><sub>Jake McGraw</sub>](http://www.jakemcgraw.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jakemcgraw "Code") | [<img src="https://avatars1.githubusercontent.com/u/1714374?v=3" width="110px;"/><br /><sub>FleischKarussel</sub>](https://github.com/FleischKarussel)<br />[📖](https://github.com/snipe/snipe-it/commits?author=FleischKarussel "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/319644?v=3" width="110px;"/><br /><sub>Dylan Yi</sub>](https://github.com/feeva)<br />[💻](https://github.com/snipe/snipe-it/commits?author=feeva "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vsposato"><img src="https://avatars2.githubusercontent.com/u/894126?v=3?s=110" width="110px;" alt="Vincent Sposato"/><br /><sub><b>Vincent Sposato</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vsposato" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/857740?v=3" width="110px;"/><br /><sub>Gil Rutkowski</sub>](http://FlashingCursor.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [<img src="https://avatars3.githubusercontent.com/u/129360?v=3" width="110px;"/><br /><sub>Desmond Morris</sub>](http://www.desmondmorris.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [<img src="https://avatars2.githubusercontent.com/u/52936?v=3" width="110px;"/><br /><sub>Nick Peelman</sub>](http://peelman.us)<br />[💻](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [<img src="https://avatars0.githubusercontent.com/u/53161?v=3" width="110px;"/><br /><sub>Abraham Vegh</sub>](https://abrahamvegh.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [<img src="https://avatars0.githubusercontent.com/u/2818680?v=3" width="110px;"/><br /><sub>Mohamed Rashid</sub>](https://github.com/rashivkp)<br />[📖](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1509456?v=3" width="110px;"/><br /><sub>Kasey</sub>](http://hinchk.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [<img src="https://avatars2.githubusercontent.com/u/10522541?v=3" width="110px;"/><br /><sub>Brett</sub>](https://github.com/BrettFagerlund)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vjandrea"><img src="https://avatars0.githubusercontent.com/u/1639757?v=3?s=110" width="110px;" alt="Andrea Bergamasco"/><br /><sub><b>Andrea Bergamasco</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vjandrea" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/16108587?v=3" width="110px;"/><br /><sub>Jason Spriggs</sub>](http://jasonspriggs.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [<img src="https://avatars2.githubusercontent.com/u/1134568?v=3" width="110px;"/><br /><sub>Nate Felton</sub>](http://n8felton.wordpress.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [<img src="https://avatars2.githubusercontent.com/u/14036694?v=3" width="110px;"/><br /><sub>Manasses Ferreira</sub>](http://homepages.dcc.ufmg.br/~manassesferreira)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [<img src="https://avatars0.githubusercontent.com/u/15913949?v=3" width="110px;"/><br /><sub>Steve</sub>](https://github.com/steveelwood)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [<img src="https://avatars1.githubusercontent.com/u/3361683?v=3" width="110px;"/><br /><sub>matc</sub>](http://twitter.com/matc)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [<img src="https://avatars3.githubusercontent.com/u/7405702?v=3" width="110px;"/><br /><sub>Cole R. Davis</sub>](http://www.davisracingteam.com)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [<img src="https://avatars2.githubusercontent.com/u/10167681?v=3" width="110px;"/><br /><sub>gibsonjoshua55</sub>](https://github.com/gibsonjoshua55)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [<img src="https://avatars1.githubusercontent.com/u/6551003?v=4" width="110px;"/><br /><sub>Richard Hofman</sub>](https://github.com/richardhofman6)<br />[💻](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [<img src="https://avatars0.githubusercontent.com/u/3697569?v=4" width="110px;"/><br /><sub>gizzmojr</sub>](https://github.com/gizzmojr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [<img src="https://avatars3.githubusercontent.com/u/404729?v=4" width="110px;"/><br /><sub>Jenny Li</sub>](https://github.com/imjennyli)<br />[📖](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/869227?v=4" width="110px;"/><br /><sub>Geoff Young</sub>](https://github.com/GeoffYoung)<br />[💻](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [<img src="https://avatars3.githubusercontent.com/u/1068477?v=4" width="110px;"/><br /><sub>Elliot Blackburn</sub>](http://www.elliotblackburn.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") |
|
||||||
<tr>
|
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18545156?v=4" width="110px;"/><br /><sub>Lawrence</sub>](https://github.com/TheVakman)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>uknzaeinozpas</sub>](https://github.com/uknzaeinozpas)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [💻](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") | [<img src="https://avatars3.githubusercontent.com/u/422752?v=4" width="110px;"/><br /><sub>Ryan</sub>](https://github.com/Gelob)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Gelob "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/10672546?v=4" width="110px;"/><br /><sub>vcordes79</sub>](https://github.com/vcordes79)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vcordes79 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kpawelski"><img src="https://avatars0.githubusercontent.com/u/10640152?v=3?s=110" width="110px;" alt="Karol"/><br /><sub><b>Karol</b></sub></a><br /><a href="#translation-kpawelski" title="Translation">🌍</a> <a href="https://github.com/snipe/snipe-it/commits?author=kpawelski" title="Code">💻</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/27958330?v=4" width="110px;"/><br /><sub>fordster78</sub>](https://github.com/fordster78)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [<img src="https://avatars0.githubusercontent.com/u/34064225?v=4" width="110px;"/><br /><sub>CronKz</sub>](https://github.com/CronKz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") [🌍](#translation-CronKz "Translation") | [<img src="https://avatars1.githubusercontent.com/u/585486?v=4" width="110px;"/><br /><sub>Tim Bishop</sub>](https://github.com/tdb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [<img src="https://avatars2.githubusercontent.com/u/5384694?v=4" width="110px;"/><br /><sub>Sean McIlvenna</sub>](https://www.seanmcilvenna.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [<img src="https://avatars3.githubusercontent.com/u/36515590?v=4" width="110px;"/><br /><sub>cepacs</sub>](https://github.com/cepacs)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [📖](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/37537300?v=4" width="110px;"/><br /><sub>lea-mink</sub>](https://github.com/lea-mink)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lea-mink "Code") | [<img src="https://avatars0.githubusercontent.com/u/7140719?v=4" width="110px;"/><br /><sub>Hannah Tinkler</sub>](https://github.com/hannahtinkler)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hannahtinkler "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://blog.morph027.de/"><img src="https://avatars3.githubusercontent.com/u/600106?v=3?s=110" width="110px;" alt="morph027"/><br /><sub><b>morph027</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=morph027" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/1086388?v=4" width="110px;"/><br /><sub>Doeke Zanstra</sub>](https://github.com/doekman)<br />[💻](https://github.com/snipe/snipe-it/commits?author=doekman "Code") | [<img src="https://avatars1.githubusercontent.com/u/4325936?v=4" width="110px;"/><br /><sub>Djamon Staal</sub>](https://www.sdhd.nl/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=SjamonDaal "Code") | [<img src="https://avatars3.githubusercontent.com/u/12306859?v=4" width="110px;"/><br /><sub>Earl Ramirez</sub>](https://github.com/EarlRamirez)<br />[💻](https://github.com/snipe/snipe-it/commits?author=EarlRamirez "Code") | [<img src="https://avatars2.githubusercontent.com/u/8671456?v=4" width="110px;"/><br /><sub>Richard Ray Thomas</sub>](https://github.com/RichardRay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=RichardRay "Code") | [<img src="https://avatars3.githubusercontent.com/u/1852688?v=4" width="110px;"/><br /><sub>Ryan Kuba</sub>](https://www.taisun.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thelamer "Code") | [<img src="https://avatars1.githubusercontent.com/u/6751928?v=4" width="110px;"/><br /><sub>Brian Monroe</sub>](https://github.com/ParadoxGuitarist)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ParadoxGuitarist "Code") | [<img src="https://avatars1.githubusercontent.com/u/605167?v=4" width="110px;"/><br /><sub>plexorama</sub>](https://github.com/plexorama)<br />[💻](https://github.com/snipe/snipe-it/commits?author=plexorama "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fvleminckx"><img src="https://avatars3.githubusercontent.com/u/22935755?v=3?s=110" width="110px;" alt="fvleminckx"/><br /><sub><b>fvleminckx</b></sub></a><br /><a href="#infra-fvleminckx" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/1795149?v=4" width="110px;"/><br /><sub>Till Deeke</sub>](https://tilldeeke.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tilldeeke "Code") | [<img src="https://avatars0.githubusercontent.com/u/12634129?v=4" width="110px;"/><br /><sub>5quirrel</sub>](https://github.com/5quirrel)<br />[💻](https://github.com/snipe/snipe-it/commits?author=5quirrel "Code") | [<img src="https://avatars1.githubusercontent.com/u/13071957?v=4" width="110px;"/><br /><sub>Jason</sub>](https://github.com/jasonlshelton)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonlshelton "Code") | [<img src="https://avatars3.githubusercontent.com/u/7128321?v=4" width="110px;"/><br /><sub>Antti</sub>](https://github.com/chemfy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chemfy "Code") | [<img src="https://avatars3.githubusercontent.com/u/10080364?v=4" width="110px;"/><br /><sub>DeusMaximus</sub>](https://github.com/DeusMaximus)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DeusMaximus "Code") | [<img src="https://avatars2.githubusercontent.com/u/16384611?v=4" width="110px;"/><br /><sub>a-royal</sub>](https://github.com/A-ROYAL)<br />[🌍](#translation-A-ROYAL "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5358208?v=4" width="110px;"/><br /><sub>Alberto Aldrigo</sub>](https://github.com/albertoaldrigo)<br />[🌍](#translation-albertoaldrigo "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/itsupportcmsukorg"><img src="https://avatars2.githubusercontent.com/u/15633547?v=3?s=110" width="110px;" alt="itsupportcmsukorg"/><br /><sub><b>itsupportcmsukorg</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=itsupportcmsukorg" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3Aitsupportcmsukorg" title="Bug reports">🐛</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/1412342?v=4" width="110px;"/><br /><sub>Alex Stanev</sub>](http://alex.stanev.org/blog)<br />[🌍](#translation-RealEnder "Translation") | [<img src="https://avatars0.githubusercontent.com/u/177295?v=4" width="110px;"/><br /><sub>Andreas Rehm</sub>](http://devel.itsolution2.de)<br />[🌍](#translation-sirrus "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5080535?v=4" width="110px;"/><br /><sub>Andreas Erhard</sub>](https://github.com/xelan)<br />[🌍](#translation-xelan "Translation") | [<img src="https://avatars2.githubusercontent.com/u/142350?v=4" width="110px;"/><br /><sub>Andrés Vanegas Jiménez</sub>](https://github.com/angeldeejay)<br />[🌍](#translation-angeldeejay "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3910403?v=4" width="110px;"/><br /><sub>Antonio Schiavon</sub>](https://github.com/aschiavon91)<br />[🌍](#translation-aschiavon91 "Translation") | [<img src="https://avatars0.githubusercontent.com/u/10464547?v=4" width="110px;"/><br /><sub>benunter</sub>](https://github.com/benunter)<br />[🌍](#translation-benunter "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5038647?v=4" width="110px;"/><br /><sub>Borys Żmuda</sub>](http://catweb24.pl)<br />[🌍](#translation-rudashi "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://override.io"><img src="https://avatars3.githubusercontent.com/u/12373799?v=3?s=110" width="110px;" alt="Frank"/><br /><sub><b>Frank</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=base-zero" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/5539359?v=4" width="110px;"/><br /><sub>chibacityblues</sub>](https://github.com/chibacityblues)<br />[🌍](#translation-chibacityblues "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1954830?v=4" width="110px;"/><br /><sub>Chien Wei Lin</sub>](https://github.com/cwlin0416)<br />[🌍](#translation-cwlin0416 "Translation") | [<img src="https://avatars3.githubusercontent.com/u/11700533?v=4" width="110px;"/><br /><sub>Christian Schuster</sub>](https://github.com/Againstreality)<br />[🌍](#translation-Againstreality "Translation") | [<img src="https://avatars1.githubusercontent.com/u/4308704?v=4" width="110px;"/><br /><sub>Christian Stefanus</sub>](http://chriss.webhostid.com)<br />[🌍](#translation-kopi-item "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3009327?v=4" width="110px;"/><br /><sub>wxcafé</sub>](http://wxcafe.net)<br />[🌍](#translation-wxcafe "Translation") | [<img src="https://avatars3.githubusercontent.com/u/35761525?v=4" width="110px;"/><br /><sub>dpyroc</sub>](https://github.com/dpyroc)<br />[🌍](#translation-dpyroc "Translation") | [<img src="https://avatars1.githubusercontent.com/u/2153639?v=4" width="110px;"/><br /><sub>Daniel Friedlmaier</sub>](http://www.friedlmaier.net)<br />[🌍](#translation-da-friedl "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ghost"><img src="https://avatars0.githubusercontent.com/u/10137?v=3?s=110" width="110px;" alt="Deleted user"/><br /><sub><b>Deleted user</b></sub></a><br /><a href="#translation-ghost" title="Translation">🌍</a> <a href="https://github.com/snipe/snipe-it/commits?author=ghost" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/2947640?v=4" width="110px;"/><br /><sub>Daniel Heene</sub>](https://github.com/danielheene)<br />[🌍](#translation-danielheene "Translation") | [<img src="https://avatars3.githubusercontent.com/u/319022?v=4" width="110px;"/><br /><sub>danielcb</sub>](https://github.com/danielcb)<br />[🌍](#translation-danielcb "Translation") | [<img src="https://avatars3.githubusercontent.com/u/15846537?v=4" width="110px;"/><br /><sub>Dominik Senti</sub>](https://github.com/dominiksenti)<br />[🌍](#translation-dominiksenti "Translation") | [<img src="https://avatars0.githubusercontent.com/u/25570954?v=4" width="110px;"/><br /><sub>Eric Gautheron</sub>](http://www.konectik.com)<br />[🌍](#translation-EpixFr "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5732623?v=4" width="110px;"/><br /><sub>Erlend Pilø</sub>](https://erlpil.com)<br />[🌍](#translation-Erlpil "Translation") | [<img src="https://avatars0.githubusercontent.com/u/541832?v=4" width="110px;"/><br /><sub>Fabio Rapposelli</sub>](http://fabio.technology)<br />[🌍](#translation-frapposelli "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3605240?v=4" width="110px;"/><br /><sub>Felipe Barros</sub>](https://github.com/fgbs)<br />[🌍](#translation-fgbs "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tiagom62"><img src="https://avatars1.githubusercontent.com/u/10802313?v=3?s=110" width="110px;" alt="tiagom62"/><br /><sub><b>tiagom62</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tiagom62" title="Code">💻</a> <a href="#infra-tiagom62" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/257745?v=4" width="110px;"/><br /><sub>Fernando Possebon</sub>](https://github.com/possebon)<br />[🌍](#translation-possebon "Translation") | [<img src="https://avatars3.githubusercontent.com/u/2540832?v=4" width="110px;"/><br /><sub>gdraque</sub>](https://github.com/gdraque)<br />[🌍](#translation-gdraque "Translation") | [<img src="https://avatars0.githubusercontent.com/u/23440381?v=4" width="110px;"/><br /><sub>Georg Wallisch</sub>](https://github.com/georgwallisch)<br />[🌍](#translation-georgwallisch "Translation") | [<img src="https://avatars1.githubusercontent.com/u/9852832?v=4" width="110px;"/><br /><sub>Gerardo Robles</sub>](https://github.com/jgroblesr85)<br />[🌍](#translation-jgroblesr85 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/11082640?v=4" width="110px;"/><br /><sub>Gluek</sub>](https://t.me/Gluek)<br />[🌍](#translation-mrgluek "Translation") | [<img src="https://avatars0.githubusercontent.com/u/6847946?v=4" width="110px;"/><br /><sub>AdnanAbuShahad</sub>](https://github.com/AdnanAbuShahad)<br />[🌍](#translation-AdnanAbuShahad "Translation") | [<img src="https://avatars1.githubusercontent.com/u/3580608?v=4" width="110px;"/><br /><sub>Hafidzi My</sub>](https://hafidzi.my)<br />[🌍](#translation-hafidzi "Translation") |
|
||||||
</tr>
|
| [<img src="https://avatars2.githubusercontent.com/u/205521?v=4" width="110px;"/><br /><sub>Harim Park</sub>](https://github.com/fofwisdom)<br />[🌍](#translation-fofwisdom "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3333841?v=4" width="110px;"/><br /><sub>Henrik Kentsson</sub>](http://www.kentsson.se)<br />[🌍](#translation-Kentsson "Translation") | [<img src="https://avatars0.githubusercontent.com/u/36551034?v=4" width="110px;"/><br /><sub>Husnul Yaqien</sub>](https://github.com/husnulyaqien)<br />[🌍](#translation-husnulyaqien "Translation") | [<img src="https://avatars1.githubusercontent.com/u/2372747?v=4" width="110px;"/><br /><sub>Ibrahim</sub>](http://abaalkhail.org)<br />[🌍](#translation-abaalkh "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1389334?v=4" width="110px;"/><br /><sub>igolman</sub>](https://github.com/igolman)<br />[🌍](#translation-igolman "Translation") | [<img src="https://avatars1.githubusercontent.com/u/3257070?v=4" width="110px;"/><br /><sub>itangiang</sub>](https://github.com/itangiang)<br />[🌍](#translation-itangiang "Translation") | [<img src="https://avatars2.githubusercontent.com/u/14814254?v=4" width="110px;"/><br /><sub>jarby1211</sub>](https://github.com/jarby1211)<br />[🌍](#translation-jarby1211 "Translation") |
|
||||||
<tr>
|
| [<img src="https://avatars3.githubusercontent.com/u/6719357?v=4" width="110px;"/><br /><sub>Jhonn Willker</sub>](http://jwillker.com)<br />[🌍](#translation-JohnWillker "Translation") | [<img src="https://avatars2.githubusercontent.com/u/10983635?v=4" width="110px;"/><br /><sub>Jose</sub>](https://github.com/joxelito94)<br />[🌍](#translation-joxelito94 "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5206122?v=4" width="110px;"/><br /><sub>laopangzi</sub>](https://github.com/laopangzi)<br />[🌍](#translation-laopangzi "Translation") | [<img src="https://avatars2.githubusercontent.com/u/79707?v=4" width="110px;"/><br /><sub>Lars Strojny</sub>](http://usrportage.de)<br />[🌍](#translation-lstrojny "Translation") | [<img src="https://avatars0.githubusercontent.com/u/389801?v=4" width="110px;"/><br /><sub>MarcosBL</sub>](http://twitter.com/marcosbl)<br />[🌍](#translation-MarcosBL "Translation") | [<img src="https://avatars3.githubusercontent.com/u/35664606?v=4" width="110px;"/><br /><sub>marie joy cajes</sub>](https://github.com/mariejoyacajes)<br />[🌍](#translation-mariejoyacajes "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3052816?v=4" width="110px;"/><br /><sub>Mark S. Johansen</sub>](http://www.markjohansen.dk)<br />[🌍](#translation-msjohansen "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rystaf"><img src="https://avatars3.githubusercontent.com/u/2389047?v=3?s=110" width="110px;" alt="Ryan Stafford"/><br /><sub><b>Ryan Stafford</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rystaf" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/982885?v=4" width="110px;"/><br /><sub>Martin Stub</sub>](http://martinstub.dk)<br />[🌍](#translation-stubben "Translation") | [<img src="https://avatars2.githubusercontent.com/u/28959963?v=4" width="110px;"/><br /><sub>Meyer Flavio</sub>](https://github.com/meyerf99)<br />[🌍](#translation-meyerf99 "Translation") | [<img src="https://avatars3.githubusercontent.com/u/796443?v=4" width="110px;"/><br /><sub>Micael Rodrigues</sub>](https://github.com/MicaelRodrigues)<br />[🌍](#translation-MicaelRodrigues "Translation") | [<img src="https://avatars0.githubusercontent.com/u/10481331?v=4" width="110px;"/><br /><sub>Mikael Rasmussen</sub>](http://rubixy.com/)<br />[🌍](#translation-mikaelssen "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1544552?v=4" width="110px;"/><br /><sub>IxFail</sub>](https://github.com/IxFail)<br />[🌍](#translation-IxFail "Translation") | [<img src="https://avatars3.githubusercontent.com/u/18483118?v=4" width="110px;"/><br /><sub>Mohammed Fota</sub>](http://www.mohammedfota.com)<br />[🌍](#translation-MohammedFota "Translation") | [<img src="https://avatars0.githubusercontent.com/u/227080?v=4" width="110px;"/><br /><sub>Moayad Alserihi</sub>](https://github.com/omego)<br />[🌍](#translation-omego "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ehanlon"><img src="https://avatars2.githubusercontent.com/u/10345935?v=3?s=110" width="110px;" alt="Eammon Hanlon"/><br /><sub><b>Eammon Hanlon</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ehanlon" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/1680266?v=4" width="110px;"/><br /><sub>saymd</sub>](https://github.com/saymd)<br />[🌍](#translation-saymd "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1826808?v=4" width="110px;"/><br /><sub>Patrik Larsson</sub>](https://nordsken.se)<br />[🌍](#translation-pooot "Translation") | [<img src="https://avatars1.githubusercontent.com/u/20584746?v=4" width="110px;"/><br /><sub>drcryo</sub>](https://github.com/drcryo)<br />[🌍](#translation-drcryo "Translation") | [<img src="https://avatars1.githubusercontent.com/u/19408004?v=4" width="110px;"/><br /><sub>pawel1615</sub>](https://github.com/pawel1615)<br />[🌍](#translation-pawel1615 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/23340468?v=4" width="110px;"/><br /><sub>bodrovics</sub>](https://github.com/bodrovics)<br />[🌍](#translation-bodrovics "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3257654?v=4" width="110px;"/><br /><sub>priatna</sub>](https://github.com/priatna)<br />[🌍](#translation-priatna "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5358374?v=4" width="110px;"/><br /><sub>Fan Jiang</sub>](https://amayume.net)<br />[🌍](#translation-ProfFan "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zjean"><img src="https://avatars0.githubusercontent.com/u/441924?v=3?s=110" width="110px;" alt="zjean"/><br /><sub><b>zjean</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=zjean" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/22555451?v=4" width="110px;"/><br /><sub>ragnarcx</sub>](https://github.com/ragnarcx)<br />[🌍](#translation-ragnarcx "Translation") | [<img src="https://avatars2.githubusercontent.com/u/18654582?v=4" width="110px;"/><br /><sub>Rein van Haaren</sub>](http://www.reinvanhaaren.nl/)<br />[🌍](#translation-reinvanhaaren "Translation") | [<img src="https://avatars1.githubusercontent.com/u/386672?v=4" width="110px;"/><br /><sub>Teguh Dwicaksana</sub>](http://dheche.songolimo.net)<br />[🌍](#translation-dheche "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2572552?v=4" width="110px;"/><br /><sub>fraccie</sub>](https://github.com/FRaccie)<br />[🌍](#translation-FRaccie "Translation") | [<img src="https://avatars0.githubusercontent.com/u/35182720?v=4" width="110px;"/><br /><sub>vinzruzell</sub>](https://github.com/vinzruzell)<br />[🌍](#translation-vinzruzell "Translation") | [<img src="https://avatars1.githubusercontent.com/u/7883603?v=4" width="110px;"/><br /><sub>Kevin Austin</sub>](http://kevinaustin.com)<br />[🌍](#translation-vipsystem "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3861828?v=4" width="110px;"/><br /><sub>Wira Sandy</sub>](http://azuraweb.xyz)<br />[🌍](#translation-wira-sandy "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.frei.media"><img src="https://avatars0.githubusercontent.com/u/12660103?v=3?s=110" width="110px;" alt="Matthias Frei"/><br /><sub><b>Matthias Frei</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=FREImedia" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [<img src="https://avatars1.githubusercontent.com/u/4930051?v=4" width="110px;"/><br /><sub>Wes Hulette</sub>](http://macfoo.wordpress.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jwhulette "Code") | [<img src="https://avatars0.githubusercontent.com/u/8134591?v=4" width="110px;"/><br /><sub>patrict</sub>](https://github.com/patrict)<br />[💻](https://github.com/snipe/snipe-it/commits?author=patrict "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/opsydev"><img src="https://avatars0.githubusercontent.com/u/3767518?v=3?s=110" width="110px;" alt="opsydev"/><br /><sub><b>opsydev</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=opsydev" title="Code">💻</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/2611616?v=4" width="110px;"/><br /><sub>Dmitriy Minaev</sub>](https://github.com/VELIKII-DIVAN)<br />[💻](https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN "Code") | [<img src="https://avatars0.githubusercontent.com/u/5132245?v=4" width="110px;"/><br /><sub>liquidhorse</sub>](https://github.com/liquidhorse)<br />[💻](https://github.com/snipe/snipe-it/commits?author=liquidhorse "Code") | [<img src="https://avatars1.githubusercontent.com/u/183678?v=4" width="110px;"/><br /><sub>Jordi Boggiano</sub>](https://seld.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Seldaek "Code") | [<img src="https://avatars0.githubusercontent.com/u/653557?v=4" width="110px;"/><br /><sub>Ivan Nieto</sub>](https://github.com/inietov)<br />[💻](https://github.com/snipe/snipe-it/commits?author=inietov "Code") | [<img src="https://avatars2.githubusercontent.com/u/6764151?v=4" width="110px;"/><br /><sub>Ben RUBSON</sub>](https://github.com/benrubson)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benrubson "Code") | [<img src="https://avatars2.githubusercontent.com/u/8554558?v=4" width="110px;"/><br /><sub>NMathar</sub>](https://github.com/NMathar)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NMathar "Code") | [<img src="https://avatars1.githubusercontent.com/u/139566?v=4" width="110px;"/><br /><sub>Steffen</sub>](https://github.com/smb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=smb "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.ddreier.com"><img src="https://avatars1.githubusercontent.com/u/82290?v=3?s=110" width="110px;" alt="Daniel Dreier"/><br /><sub><b>Daniel Dreier</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ddreier" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/6609453?v=4" width="110px;"/><br /><sub>Sxderp</sub>](https://github.com/Sxderp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Sxderp "Code") | [<img src="https://avatars1.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>fanta8897</sub>](https://github.com/fanta8897)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fanta8897 "Code") | [<img src="https://avatars2.githubusercontent.com/u/2576509?v=4" width="110px;"/><br /><sub>Andrey Bolonin</sub>](https://andreybolonin.com/phpconsulting/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreybolonin "Code") | [<img src="https://avatars3.githubusercontent.com/u/2173307?v=4" width="110px;"/><br /><sub>shinayoshi</sub>](http://www.shinayoshi.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=shinayoshi "Code") | [<img src="https://avatars3.githubusercontent.com/u/2130159?v=4" width="110px;"/><br /><sub>Hubert</sub>](https://github.com/reuser)<br />[💻](https://github.com/snipe/snipe-it/commits?author=reuser "Code") | [<img src="https://avatars0.githubusercontent.com/u/6865789?v=4" width="110px;"/><br /><sub>KeenRivals</sub>](https://brashear.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KeenRivals "Code") | [<img src="https://avatars3.githubusercontent.com/u/2902513?v=4" width="110px;"/><br /><sub>omyno</sub>](https://github.com/omyno)<br />[💻](https://github.com/snipe/snipe-it/commits?author=omyno "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://rassie.org"><img src="https://avatars0.githubusercontent.com/u/23448?v=3?s=110" width="110px;" alt="Nikolai Prokoschenko"/><br /><sub><b>Nikolai Prokoschenko</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rassie" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/6271335?v=4" width="110px;"/><br /><sub>Evgeny</sub>](https://github.com/jackka)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jackka "Code") | [<img src="https://avatars2.githubusercontent.com/u/1169963?v=4" width="110px;"/><br /><sub>Colin Campbell</sub>](https://digitalist.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=colin-campbell "Code") | [<img src="https://avatars3.githubusercontent.com/u/2872098?v=4" width="110px;"/><br /><sub>Ľubomír Kučera</sub>](https://github.com/lubo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lubo "Code") | [<img src="https://avatars3.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://www.sourceguru.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Mezzle "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [<img src="https://avatars0.githubusercontent.com/u/17459600?v=4" width="110px;"/><br /><sub>Marián Skrip</sub>](https://github.com/mskrip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") | [<img src="https://avatars2.githubusercontent.com/u/47435081?v=4" width="110px;"/><br /><sub>Godfrey Martinez</sub>](https://github.com/Godmartinz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars1.githubusercontent.com/u/2075128?v=4" width="110px;"/><br /><sub>bigtreeEdo</sub>](https://github.com/bigtreeEdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [<img src="https://avatars0.githubusercontent.com/u/5000430?v=4" width="110px;"/><br /><sub>Colin McNeil</sub>](https://colinmcneil.me/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [<img src="https://avatars0.githubusercontent.com/u/421625?v=4" width="110px;"/><br /><sub>JoKneeMo</sub>](https://github.com/JoKneeMo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [<img src="https://avatars0.githubusercontent.com/u/54849013?v=4" width="110px;"/><br /><sub>Joshi</sub>](http://www.redbridge.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [<img src="https://avatars2.githubusercontent.com/u/15731458?v=4" width="110px;"/><br /><sub>Anthony Burns</sub>](https://github.com/anthonypburns)<br />[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [<img src="https://avatars1.githubusercontent.com/u/63399474?v=4" width="110px;"/><br /><sub>johnson-yi</sub>](https://github.com/johnson-yi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=johnson-yi "Code") | [<img src="https://avatars1.githubusercontent.com/u/1862720?v=4" width="110px;"/><br /><sub>Sanjay Govind</sub>](https://tangentmc.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sanjay900 "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars0.githubusercontent.com/u/1255375?v=4" width="110px;"/><br /><sub>Peter Upfold</sub>](https://peter.upfold.org.uk/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PeterUpfold "Code") | [<img src="https://avatars2.githubusercontent.com/u/961717?v=4" width="110px;"/><br /><sub>Jared Biel</sub>](https://github.com/jbiel)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jbiel "Code") | [<img src="https://avatars1.githubusercontent.com/u/1733625?v=4" width="110px;"/><br /><sub>Dampfklon</sub>](https://github.com/dampfklon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dampfklon "Code") | [<img src="https://avatars2.githubusercontent.com/u/52973156?v=4" width="110px;"/><br /><sub>Charles Hamilton</sub>](https://communityclosing.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chamilton-ccn "Code") | [<img src="https://avatars.githubusercontent.com/u/551789?v=4" width="110px;"/><br /><sub>Giuseppe Iannello</sub>](https://github.com/giannello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=giannello "Code") | [<img src="https://avatars.githubusercontent.com/u/3691490?v=4" width="110px;"/><br /><sub>Peter Dave Hello</sub>](https://www.peterdavehello.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PeterDaveHello "Code") | [<img src="https://avatars.githubusercontent.com/u/6106332?v=4" width="110px;"/><br /><sub>sigmoidal</sub>](https://github.com/sigmoidal)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sigmoidal "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YetAnotherCodeMonkey"><img src="https://avatars0.githubusercontent.com/u/13452757?v=3?s=110" width="110px;" alt="Drew"/><br /><sub><b>Drew</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=YetAnotherCodeMonkey" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/2082554?v=4" width="110px;"/><br /><sub>Vincent Lainé</sub>](https://github.com/phenixdotnet)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phenixdotnet "Code") | [<img src="https://avatars.githubusercontent.com/u/1943040?v=4" width="110px;"/><br /><sub>Lucas Pleß</sub>](http://www.lucas-pless.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derlucas "Code") | [<img src="https://avatars.githubusercontent.com/u/472804?v=4" width="110px;"/><br /><sub>Ian Littman</sub>](http://twitter.com/iansltx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=iansltx "Code") | [<img src="https://avatars.githubusercontent.com/u/3519029?v=4" width="110px;"/><br /><sub>João Paulo</sub>](https://github.com/PauloLuna)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PauloLuna "Code") | [<img src="https://avatars.githubusercontent.com/u/70443365?v=4" width="110px;"/><br /><sub>ThoBur</sub>](https://github.com/ThoBur)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ThoBur "Code") | [<img src="https://avatars.githubusercontent.com/u/1972329?v=4" width="110px;"/><br /><sub>Alexander Chibrikin</sub>](http://phpprofi.ru/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alek13 "Code") | [<img src="https://avatars.githubusercontent.com/u/438332?v=4" width="110px;"/><br /><sub>Anthony Winstanley</sub>](https://github.com/winstan)<br />[💻](https://github.com/snipe/snipe-it/commits?author=winstan "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/merid14"><img src="https://avatars0.githubusercontent.com/u/1342320?v=3?s=110" width="110px;" alt="Walter"/><br /><sub><b>Walter</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=merid14" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/3075214?v=4" width="110px;"/><br /><sub>Folke</sub>](https://github.com/fashberg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fashberg "Code") | [<img src="https://avatars.githubusercontent.com/u/1351571?v=4" width="110px;"/><br /><sub>Bennett Blodinger</sub>](https://github.com/benwa)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benwa "Code") | [<img src="https://avatars.githubusercontent.com/u/2974631?v=4" width="110px;"/><br /><sub>NMC</sub>](https://nmc.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ncareau "Code") | [<img src="https://avatars.githubusercontent.com/u/52182449?v=4" width="110px;"/><br /><sub>andres-baller</sub>](https://github.com/andres-baller)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andres-baller "Code") | [<img src="https://avatars.githubusercontent.com/u/67109348?v=4" width="110px;"/><br /><sub>sean-borg</sub>](https://github.com/sean-borg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sean-borg "Code") | [<img src="https://avatars.githubusercontent.com/u/32170051?v=4" width="110px;"/><br /><sub>EDVLeer</sub>](https://github.com/EDVLeer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=EDVLeer "Code") | [<img src="https://avatars.githubusercontent.com/u/23075196?v=4" width="110px;"/><br /><sub>Kurokat</sub>](https://github.com/Kurokat)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Kurokat "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/balous"><img src="https://avatars3.githubusercontent.com/u/11254614?v=3?s=110" width="110px;" alt="Petr Baloun"/><br /><sub><b>Petr Baloun</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=balous" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/915514?v=4" width="110px;"/><br /><sub>Kevin Köllmann</sub>](https://www.kevinkoellmann.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koelle25 "Code") | [<img src="https://avatars.githubusercontent.com/u/49025941?v=4" width="110px;"/><br /><sub>sw-mreyes</sub>](https://github.com/sw-mreyes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sw-mreyes "Code") | [<img src="https://avatars.githubusercontent.com/u/70129?v=4" width="110px;"/><br /><sub>Joel Pittet</sub>](https://pittet.ca)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joelpittet "Code") | [<img src="https://avatars.githubusercontent.com/u/792695?v=4" width="110px;"/><br /><sub>Eli Young</sub>](https://elyscape.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=elyscape "Code") | [<img src="https://avatars.githubusercontent.com/u/317015?v=4" width="110px;"/><br /><sub>Raell Dottin</sub>](https://github.com/raelldottin)<br />[💻](https://github.com/snipe/snipe-it/commits?author=raelldottin "Code") | [<img src="https://avatars.githubusercontent.com/u/1446856?v=4" width="110px;"/><br /><sub>Tom Misilo</sub>](https://github.com/misilot)<br />[💻](https://github.com/snipe/snipe-it/commits?author=misilot "Code") | [<img src="https://avatars.githubusercontent.com/u/4496300?v=4" width="110px;"/><br /><sub>David Davenne</sub>](http://david.davenne.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JuustoMestari "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/reidblomquist"><img src="https://avatars0.githubusercontent.com/u/6117660?v=3?s=110" width="110px;" alt="reidblomquist"/><br /><sub><b>reidblomquist</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=reidblomquist" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mathieuk"><img src="https://avatars0.githubusercontent.com/u/539914?v=3?s=110" width="110px;" alt="Mathieu Kooiman"/><br /><sub><b>Mathieu Kooiman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mathieuk" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/csayre"><img src="https://avatars3.githubusercontent.com/u/6606421?v=3?s=110" width="110px;" alt="csayre"/><br /><sub><b>csayre</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=csayre" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [<img src="https://avatars.githubusercontent.com/u/11973217?v=4" width="110px;"/><br /><sub>tbrconnect</sub>](https://github.com/tbrconnect)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") | [<img src="https://avatars.githubusercontent.com/u/12447225?v=4" width="110px;"/><br /><sub>kcoyo</sub>](https://github.com/kcoyo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kcoyo "Code") | [<img src="https://avatars.githubusercontent.com/u/494017?v=4" width="110px;"/><br /><sub>Travis Miller</sub>](https://travismiller.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=travismiller "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/adamdunson"><img src="https://avatars1.githubusercontent.com/u/768488?v=3?s=110" width="110px;" alt="Adam Dunson"/><br /><sub><b>Adam Dunson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=adamdunson" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/thehereward"><img src="https://avatars0.githubusercontent.com/u/5547470?v=3?s=110" width="110px;" alt="Hereward"/><br /><sub><b>Hereward</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=thehereward" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/qveensi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qveensi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/swoopdk"><img src="https://avatars0.githubusercontent.com/u/5802977?v=3?s=110" width="110px;" alt="swoopdk"/><br /><sub><b>swoopdk</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=swoopdk" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") | [<img src="https://avatars.githubusercontent.com/u/7991086?v=4" width="110px;"/><br /><sub>Daniel Reeder</sub>](https://github.com/reederda)<br />[🌍](#translation-reederda "Translation") [🌍](#translation-reederda "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=reederda "Code") | [<img src="https://avatars.githubusercontent.com/u/109422491?v=4" width="110px;"/><br /><sub>vickyjaura183</sub>](https://github.com/vickyjaura183)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vickyjaura183 "Code") | [<img src="https://avatars.githubusercontent.com/u/32363424?v=4" width="110px;"/><br /><sub>Peace</sub>](https://github.com/julian-piehl)<br />[💻](https://github.com/snipe/snipe-it/commits?author=julian-piehl "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://linkedin.com/in/ahimta"><img src="https://avatars1.githubusercontent.com/u/3470403?v=3?s=110" width="110px;" alt="Abdullah Alansari"/><br /><sub><b>Abdullah Alansari</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Ahimta" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/231528?v=4" width="110px;"/><br /><sub>Kyle Gordon</sub>](https://github.com/kylegordon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kylegordon "Code") | [<img src="https://avatars.githubusercontent.com/u/53009155?v=4" width="110px;"/><br /><sub>Katharina Drexel</sub>](http://www.bfh.ch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sunflowerbofh "Code") | [<img src="https://avatars.githubusercontent.com/u/1931963?v=4" width="110px;"/><br /><sub>David Sferruzza</sub>](https://david.sferruzza.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dsferruzza "Code") | [<img src="https://avatars.githubusercontent.com/u/19511639?v=4" width="110px;"/><br /><sub>Rick Nelson</sub>](https://github.com/rnelsonee)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rnelsonee "Code") | [<img src="https://avatars.githubusercontent.com/u/94169344?v=4" width="110px;"/><br /><sub>BasO12</sub>](https://github.com/BasO12)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BasO12 "Code") | [<img src="https://avatars.githubusercontent.com/u/111710123?v=4" width="110px;"/><br /><sub>Vautia</sub>](https://github.com/Vautia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Vautia "Code") | [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MicaelRodrigues"><img src="https://avatars0.githubusercontent.com/u/796443?v=3?s=110" width="110px;" alt="Micael Rodrigues"/><br /><sub><b>Micael Rodrigues</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=MicaelRodrigues" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") | [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://macadmincorner.com"><img src="https://avatars0.githubusercontent.com/u/614564?v=3?s=110" width="110px;" alt="Patrick Gallagher"/><br /><sub><b>Patrick Gallagher</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=patgmac" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") | [<img src="https://avatars.githubusercontent.com/u/658865?v=4" width="110px;"/><br /><sub>Andrew Savinykh</sub>](https://github.com/AndrewSav)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AndrewSav "Code") | [<img src="https://avatars.githubusercontent.com/u/1155067?v=4" width="110px;"/><br /><sub>Tadayuki Onishi</sub>](https://kenchan0130.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kenchan0130 "Code") | [<img src="https://avatars.githubusercontent.com/u/112496896?v=4" width="110px;"/><br /><sub>Florian</sub>](https://github.com/floschoepfer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=floschoepfer "Code") | [<img src="https://avatars.githubusercontent.com/u/7305753?v=4" width="110px;"/><br /><sub>Spencer Long</sub>](http://spencerlong.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=spencerrlongg "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Miliamber"><img src="https://avatars3.githubusercontent.com/u/7165922?v=3?s=110" width="110px;" alt="Miliamber"/><br /><sub><b>Miliamber</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Miliamber" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/1141514?v=4" width="110px;"/><br /><sub>Marcus Moore</sub>](https://github.com/marcusmoore)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcusmoore "Code") | [<img src="https://avatars.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://github.com/Mezzle)<br /> | [<img src="https://avatars.githubusercontent.com/u/5731963?v=4" width="110px;"/><br /><sub>dboth</sub>](http://dboth.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dboth "Code") | [<img src="https://avatars.githubusercontent.com/u/87536651?v=4" width="110px;"/><br /><sub>Zachary Fleck</sub>](https://github.com/zacharyfleck)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zacharyfleck "Code") | [<img src="https://avatars.githubusercontent.com/u/74609912?v=4" width="110px;"/><br /><sub>VIKAAS-A</sub>](https://github.com/vikaas-cyper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vikaas-cyper "Code") | [<img src="https://avatars.githubusercontent.com/u/88882041?v=4" width="110px;"/><br /><sub>Abdul Kareem</sub>](https://github.com/ak-piracha)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ak-piracha "Code") | [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hawk554"><img src="https://avatars3.githubusercontent.com/u/861766?v=3?s=110" width="110px;" alt="hawk554"/><br /><sub><b>hawk554</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=hawk554" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [<img src="https://avatars.githubusercontent.com/u/58479551?v=4" width="110px;"/><br /><sub>Bogdan</sub>](http://@singrity)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") | [<img src="https://avatars.githubusercontent.com/u/3483684?v=4" width="110px;"/><br /><sub>mmanjos</sub>](https://github.com/mmanjos)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mmanjos "Code") | [<img src="https://avatars.githubusercontent.com/u/7429229?v=4" width="110px;"/><br /><sub>Abdelaziz Faki</sub>](https://azooz2014.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azooz2014 "Code") | [<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") |
|
||||||
</tr>
|
| [<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") |
|
||||||
<tr>
|
| [<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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jbirdkerr.net"><img src="https://avatars1.githubusercontent.com/u/1695622?v=3?s=110" width="110px;" alt="Justin Kerr"/><br /><sub><b>Justin Kerr</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jbirdkerr" title="Code">💻</a></td>
|
| [<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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.irasnyder.com/devel/"><img src="https://avatars3.githubusercontent.com/u/11426176?v=3?s=110" width="110px;" alt="Ira W. Snyder"/><br /><sub><b>Ira W. Snyder</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=irasnyd" title="Documentation">📖</a></td>
|
| [<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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aalaily"><img src="https://avatars2.githubusercontent.com/u/2475759?v=3?s=110" width="110px;" alt="Aladin Alaily"/><br /><sub><b>Aladin Alaily</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=aalaily" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/18550946?v=4" width="110px;"/><br /><sub>Adugna Gizaw</sub>](https://orbalia.pythonanywhere.com/)<br />[🌍](#translation-addex12 "Translation") | [<img src="https://avatars.githubusercontent.com/u/760989?v=4" width="110px;"/><br /><sub>Jesse Ostrander</sub>](https://github.com/jostrander)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") | [<img src="https://avatars.githubusercontent.com/u/31522486?v=4" width="110px;"/><br /><sub>James M</sub>](https://github.com/azmcnutt)<br />[💻](https://github.com/snipe/snipe-it/commits?author=azmcnutt "Code") | [<img src="https://avatars.githubusercontent.com/u/5183146?v=4" width="110px;"/><br /><sub>Fiala06</sub>](https://github.com/Fiala06)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Fiala06 "Code") | [<img src="https://avatars.githubusercontent.com/u/28693782?v=4" width="110px;"/><br /><sub>Nathan Taylor</sub>](https://github.com/ntaylor-86)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntaylor-86 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kobie-chasehansen"><img src="https://avatars0.githubusercontent.com/u/10247644?v=3?s=110" width="110px;" alt="Chase Hansen"/><br /><sub><b>Chase Hansen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=kobie-chasehansen" title="Code">💻</a> <a href="#question-kobie-chasehansen" title="Answering Questions">💬</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3Akobie-chasehansen" title="Bug reports">🐛</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/16699443?v=4" width="110px;"/><br /><sub>fvollmer</sub>](https://github.com/fvollmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fvollmer "Code") | [<img src="https://avatars.githubusercontent.com/u/109086466?v=4" width="110px;"/><br /><sub>36864</sub>](https://github.com/36864)<br />[💻](https://github.com/snipe/snipe-it/commits?author=36864 "Code") | [<img src="https://avatars.githubusercontent.com/u/365751?v=4" width="110px;"/><br /><sub>Daniel O'Connor</sub>](http://clockwerx.blogspot.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CloCkWeRX "Code") | [<img src="https://avatars.githubusercontent.com/u/102852568?v=4" width="110px;"/><br /><sub>BeatSpark</sub>](https://github.com/BeatSpark)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BeatSpark "Code") | [<img src="https://avatars.githubusercontent.com/u/59203607?v=4" width="110px;"/><br /><sub>mrdahbi</sub>](https://github.com/mrdahbi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrdahbi "Code") | [<img src="https://avatars.githubusercontent.com/u/6661332?v=4" width="110px;"/><br /><sub>Fabian Schmid</sub>](http://sr.solutions)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chfsx "Code") | [<img src="https://avatars.githubusercontent.com/u/1288116?v=4" width="110px;"/><br /><sub>Chris Olin</sub>](https://www.chrisolin.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=realchrisolin "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IDM-Helpdesk"><img src="https://avatars2.githubusercontent.com/u/13545400?v=3?s=110" width="110px;" alt="IDM Helpdesk"/><br /><sub><b>IDM Helpdesk</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=IDM-Helpdesk" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/3803132?v=4" width="110px;"/><br /><sub>Dan</sub>](https://github.com/mnemonicly)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mnemonicly "Code") | [<img src="https://avatars.githubusercontent.com/u/43917728?v=4" width="110px;"/><br /><sub>Nebel</sub>](https://github.com/NebelKreis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NebelKreis "Code") | [<img src="https://avatars.githubusercontent.com/u/132433803?v=4" width="110px;"/><br /><sub>test1337ahp</sub>](https://github.com/test1337ahp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=test1337ahp "Code") | [<img src="https://avatars.githubusercontent.com/u/1916566?v=4" width="110px;"/><br /><sub>Jonathon Reinhart</sub>](https://github.com/JonathonReinhart)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JonathonReinhart "Code") | [<img src="https://avatars.githubusercontent.com/u/484742?v=4" width="110px;"/><br /><sub>aranar-pro</sub>](https://github.com/aranar-pro)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aranar-pro "Code") | [<img src="https://avatars.githubusercontent.com/u/27019397?v=4" width="110px;"/><br /><sub>Phil</sub>](https://github.com/phil-flip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phil-flip "Code") | [<img src="https://avatars.githubusercontent.com/u/6473460?v=4" width="110px;"/><br /><sub>Steffy Fort</sub>](https://fe80.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fe80 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://balticer.de"><img src="https://avatars2.githubusercontent.com/u/614439?v=3?s=110" width="110px;" alt="Kai"/><br /><sub><b>Kai</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=balticer" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/3302372?v=4" width="110px;"/><br /><sub>Jared Busch</sub>](https://github.com/sorvani)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sorvani "Code") | [<img src="https://avatars.githubusercontent.com/u/111956991?v=4" width="110px;"/><br /><sub>seanborg-codethink</sub>](https://github.com/seanborg-codethink)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanborg-codethink "Code") | [<img src="https://avatars.githubusercontent.com/u/160669961?v=4" width="110px;"/><br /><sub>dkaatz</sub>](https://github.com/dkaatz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dkaatz "Code") | [<img src="https://avatars.githubusercontent.com/u/827205?v=4" width="110px;"/><br /><sub>Daniel Ruf</sub>](https://threema.id/74SF7MW6?text=)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DanielRuf "Code") | [<img src="https://avatars.githubusercontent.com/u/38883201?v=4" width="110px;"/><br /><sub>ahpaleus</sub>](https://github.com/ahpaleus)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ahpaleus "Code") | [<img src="https://avatars.githubusercontent.com/u/22906055?v=4" width="110px;"/><br /><sub>Anh DAO-DUY</sub>](https://github.com/mink-adao-duy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mink-adao-duy "Code") | [<img src="https://avatars.githubusercontent.com/u/4723453?v=4" width="110px;"/><br /><sub>Andres Gutierrez</sub>](https://github.com/Serdnad)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Serdnad "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.michaeldaniels.me"><img src="https://avatars1.githubusercontent.com/u/8762511?v=3?s=110" width="110px;" alt="Michael Daniels"/><br /><sub><b>Michael Daniels</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mdaniels5757" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/111083379?v=4" width="110px;"/><br /><sub>Warren White</sub>](https://github.com/wewhite)<br />[💻](https://github.com/snipe/snipe-it/commits?author=wewhite "Code") | [<img src="https://avatars.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://robintemme.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=robintemme "Code") | [<img src="https://avatars.githubusercontent.com/u/47008367?v=4" width="110px;"/><br /><sub>herroworrd</sub>](https://github.com/herroworrd)<br />[💻](https://github.com/snipe/snipe-it/commits?author=herroworrd "Code") | [<img src="https://avatars.githubusercontent.com/u/28558609?v=4" width="110px;"/><br /><sub>vicleos</sub>](https://mubiu.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vicleos "Code") | [<img src="https://avatars.githubusercontent.com/u/1016780?v=4" width="110px;"/><br /><sub>Bob Clough</sub>](http://thinkl33t.co.uk/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thinkl33t "Code") | [<img src="https://avatars.githubusercontent.com/u/10648463?v=4" width="110px;"/><br /><sub>Brandon Daniel Bailey</sub>](https://github.com/brandon-bailey)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brandon-bailey "Code") | [<img src="https://avatars.githubusercontent.com/u/23556080?v=4" width="110px;"/><br /><sub>Marc Bartelt</sub>](https://github.com/marcquark)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcquark "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars.githubusercontent.com/u/18286893?v=4" width="110px;"/><br /><sub>manu-crealytics</sub>](https://github.com/manu-crealytics)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manu-crealytics "Code") | [<img src="https://avatars.githubusercontent.com/u/18245993?v=4" width="110px;"/><br /><sub>Konstantin Köhring</sub>](https://www.galaxy102.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Galaxy102 "Code") | [<img src="https://avatars.githubusercontent.com/u/685167?v=4" width="110px;"/><br /><sub>Deloz</sub>](https://deloz.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deloz "Code") | [<img src="https://avatars.githubusercontent.com/u/2682426?v=4" width="110px;"/><br /><sub>Martin Berg</sub>](https://github.com/mbrrg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mbrrg "Code") | [<img src="https://avatars.githubusercontent.com/u/3694534?v=4" width="110px;"/><br /><sub>Richard Schwab</sub>](https://github.com/Nothing4You)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Nothing4You "Code") | [<img src="https://avatars.githubusercontent.com/u/8959676?v=4" width="110px;"/><br /><sub>Rick Heil</sub>](https://rickheil.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rickheil "Code") | [<img src="https://avatars.githubusercontent.com/u/397106?v=4" width="110px;"/><br /><sub>Ross Crawford-d'Heureuse</sub>](https://github.com/rosscdh)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rosscdh "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars.githubusercontent.com/u/1621107?v=4" width="110px;"/><br /><sub>Ryan McGuire</sub>](https://github.com/McG800)<br />[💻](https://github.com/snipe/snipe-it/commits?author=McG800 "Code") | [<img src="https://avatars.githubusercontent.com/u/77835667?v=4" width="110px;"/><br /><sub>SBrown2021</sub>](https://github.com/SBrown2021)<br />[💻](https://github.com/snipe/snipe-it/commits?author=SBrown2021 "Code") | [<img src="https://avatars.githubusercontent.com/u/8780913?v=4" width="110px;"/><br /><sub>Serkan</sub>](https://github.com/serkanerip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=serkanerip "Code") | [<img src="https://avatars.githubusercontent.com/u/63188620?v=4" width="110px;"/><br /><sub>Shanks</sub>](https://www.yudelei.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Shankschn "Code") | [<img src="https://avatars.githubusercontent.com/u/198525698?v=4" width="110px;"/><br /><sub>cendai-mis</sub>](https://github.com/cendai-mis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cendai-mis "Code") | [<img src="https://avatars.githubusercontent.com/u/8724583?v=4" width="110px;"/><br /><sub>Shaun McPeck</sub>](https://smcpeck.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=smcpeck "Code") | [<img src="https://avatars.githubusercontent.com/u/1378836?v=4" width="110px;"/><br /><sub>Stephen</sub>](https://github.com/snazy2000)<br />[💻](https://github.com/snipe/snipe-it/commits?author=snazy2000 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://tomcastleman.me"><img src="https://avatars3.githubusercontent.com/u/1532660?v=3?s=110" width="110px;" alt="Tom Castleman"/><br /><sub><b>Tom Castleman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tomcastleman" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/4462739?v=4" width="110px;"/><br /><sub>Steven</sub>](http://nevets82.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Nevets82 "Code") | [<img src="https://avatars.githubusercontent.com/u/29017267?v=4" width="110px;"/><br /><sub>Mateus Villar</sub>](https://mateusvillar.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Mateus-Romera "Code") | [<img src="https://avatars.githubusercontent.com/u/12749393?v=4" width="110px;"/><br /><sub>Matthew Zackschewski</sub>](https://github.com/mzack5020)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mzack5020 "Code") | [<img src="https://avatars.githubusercontent.com/u/12660103?v=4" width="110px;"/><br /><sub>Matthias Frei</sub>](https://www.frei.media/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=firefrei "Code") | [<img src="https://avatars.githubusercontent.com/u/824840?v=4" width="110px;"/><br /><sub>Nenad Ticaric</sub>](https://github.com/nticaric)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nticaric "Code") | [<img src="https://avatars.githubusercontent.com/u/706439?v=4" width="110px;"/><br /><sub>Nikolay Didenko</sub>](https://github.com/Scorcher)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scorcher "Code") | [<img src="https://avatars.githubusercontent.com/u/5457236?v=4" width="110px;"/><br /><sub>Nuno Maduro</sub>](https://nunomaduro.com/sponsorships)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nunomaduro "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DanielNemanic"><img src="https://avatars3.githubusercontent.com/u/10723243?v=3?s=110" width="110px;" alt="Daniel Nemanic"/><br /><sub><b>Daniel Nemanic</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=DanielNemanic" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/8883074?v=4" width="110px;"/><br /><sub>Oliver Walerys</sub>](https://tektikhq.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=owalerys "Code") | [<img src="https://avatars.githubusercontent.com/u/3102039?v=4" width="110px;"/><br /><sub>R. Christian McDonald</sub>](https://keybase.io/rcmcdonald91)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rcmcdonald91 "Code") | [<img src="https://avatars.githubusercontent.com/u/1525581?v=4" width="110px;"/><br /><sub>nix</sub>](https://nnix.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nixn "Code") | [<img src="https://avatars.githubusercontent.com/u/55462380?v=4" width="110px;"/><br /><sub>octobunny</sub>](https://github.com/octobunny)<br />[💻](https://github.com/snipe/snipe-it/commits?author=octobunny "Code") | [<img src="https://avatars.githubusercontent.com/u/8558670?v=4" width="110px;"/><br /><sub>Ryan</sub>](https://github.com/sreyemnayr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sreyemnayr "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>p3nj</sub>](https://benji.ltd/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=p3nj "Code") | [<img src="https://avatars.githubusercontent.com/u/6201617?v=4" width="110px;"/><br /><sub>Tim White</sub>](https://github.com/timwsuqld)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timwsuqld "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/southwolf"><img src="https://avatars0.githubusercontent.com/u/150648?v=3?s=110" width="110px;" alt="SouthWolf"/><br /><sub><b>SouthWolf</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=southwolf" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>yannikp</sub>](https://github.com/yannikp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=yannikp "Code") | [<img src="https://avatars.githubusercontent.com/u/20525448?v=4" width="110px;"/><br /><sub>victoria</sub>](https://github.com/viclou)<br />[💻](https://github.com/snipe/snipe-it/commits?author=viclou "Code") | [<img src="https://avatars.githubusercontent.com/u/40685314?v=4" width="110px;"/><br /><sub>Valentyn Tulub</sub>](https://github.com/valentyntu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=valentyntu "Code") | [<img src="https://avatars.githubusercontent.com/u/864520?v=4" width="110px;"/><br /><sub>Wouter van Os</sub>](http://wouter0100.nl/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Wouter0100 "Code") | [<img src="https://avatars.githubusercontent.com/u/3946540?v=4" width="110px;"/><br /><sub>Wyatt Teeter</sub>](https://www.linkedin.com/in/wyatt-teeter)<br />[💻](https://github.com/snipe/snipe-it/commits?author=xWyatt "Code") | [<img src="https://avatars.githubusercontent.com/u/1596124?v=4" width="110px;"/><br /><sub>Yorick Terweijden</sub>](https://github.com/terwey)<br />[💻](https://github.com/snipe/snipe-it/commits?author=terwey "Code") | [<img src="https://avatars.githubusercontent.com/u/69298836?v=4" width="110px;"/><br /><sub>bmkalle</sub>](https://github.com/bmkalle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bmkalle "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ivarne"><img src="https://avatars2.githubusercontent.com/u/131616?v=3?s=110" width="110px;" alt="Ivar Nesje"/><br /><sub><b>Ivar Nesje</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ivarne" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/28403467?v=4" width="110px;"/><br /><sub>bricelabelle</sub>](https://github.com/bricelabelle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bricelabelle "Code") | [<img src="https://avatars.githubusercontent.com/u/97770090?v=4" width="110px;"/><br /><sub>corydlamb</sub>](https://github.com/corydlamb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=corydlamb "Code") | [<img src="https://avatars.githubusercontent.com/u/1154133?v=4" width="110px;"/><br /><sub>Diogenes S. Jesus</sub>](http://twitter.com/splash)<br />[💻](https://github.com/snipe/snipe-it/commits?author=splashx "Code") | [<img src="https://avatars.githubusercontent.com/u/5826629?v=4" width="110px;"/><br /><sub>D M</sub>](https://github.com/dkmansion)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dkmansion "Code") | [<img src="https://avatars.githubusercontent.com/u/14837699?v=4" width="110px;"/><br /><sub>Dustin B</sub>](https://github.com/Jarli01)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jarli01 "Code") | [<img src="https://avatars.githubusercontent.com/u/348344?v=4" width="110px;"/><br /><sub>Fabian Grutschus</sub>](https://github.com/fabiang)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fabiang "Code") | [<img src="https://avatars.githubusercontent.com/u/1491053?v=4" width="110px;"/><br /><sub>MelonSmasher</sub>](https://github.com/MelonSmasher)<br />[💻](https://github.com/snipe/snipe-it/commits?author=MelonSmasher "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.j0k3r.net"><img src="https://avatars1.githubusercontent.com/u/62333?v=3?s=110" width="110px;" alt="Jérémy Benoist"/><br /><sub><b>Jérémy Benoist</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=j0k3r" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/80526133?v=4" width="110px;"/><br /><sub>AlexanderWPapyrus</sub>](https://github.com/AlexanderWPapyrus)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AlexanderWPapyrus "Code") | [<img src="https://avatars.githubusercontent.com/u/306231?v=4" width="110px;"/><br /><sub>Alexandr Hacicheant</sub>](https://github.com/disc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=disc "Code") | [<img src="https://avatars.githubusercontent.com/u/3032891?v=4" width="110px;"/><br /><sub>Hex</sub>](https://hex128.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hex128 "Code") | [<img src="https://avatars.githubusercontent.com/u/8697942?v=4" width="110px;"/><br /><sub>Arunas Skirius</sub>](https://github.com/arukompas)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arukompas "Code") | [<img src="https://avatars.githubusercontent.com/u/104396?v=4" width="110px;"/><br /><sub>Ben Periton</sub>](https://github.com/benperiton)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benperiton "Code") | [<img src="https://avatars.githubusercontent.com/u/11906832?v=4" width="110px;"/><br /><sub>Byron Wolfman</sub>](https://wolfman.dev/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=byronwolfman "Code") | [<img src="https://avatars.githubusercontent.com/u/56485508?v=4" width="110px;"/><br /><sub>Calvin</sub>](https://github.com/CalvinSchwartz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CalvinSchwartz "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cleathley"><img src="https://avatars2.githubusercontent.com/u/724344?v=3?s=110" width="110px;" alt="Chris Leathley"/><br /><sub><b>Chris Leathley</b></sub></a><br /><a href="#infra-cleathley" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/181059?v=4" width="110px;"/><br /><sub>Juan Font</sub>](https://github.com/juanfont)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juanfont "Code") | [<img src="https://avatars.githubusercontent.com/u/13137708?v=4" width="110px;"/><br /><sub>Juho Taipale</sub>](https://github.com/juhotaipale)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juhotaipale "Code") | [<img src="https://avatars.githubusercontent.com/u/1007419?v=4" width="110px;"/><br /><sub>Korvin Szanto</sub>](https://github.com/KorvinSzanto)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KorvinSzanto "Code") | [<img src="https://avatars.githubusercontent.com/u/8513053?v=4" width="110px;"/><br /><sub>Lewis Foster</sub>](https://lewisfoster.foo/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sniff122 "Code") | [<img src="https://avatars.githubusercontent.com/u/33877541?v=4" width="110px;"/><br /><sub>Logan Swartzendruber</sub>](https://github.com/loganswartz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=loganswartz "Code") | [<img src="https://avatars.githubusercontent.com/u/1156208?v=4" width="110px;"/><br /><sub>Lorenzo P.</sub>](https://github.com/lopezio)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lopezio "Code") | [<img src="https://avatars.githubusercontent.com/u/33946590?v=4" width="110px;"/><br /><sub>Lukas Jung</sub>](https://github.com/m4us1ne)<br />[💻](https://github.com/snipe/snipe-it/commits?author=m4us1ne "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/splaer"><img src="https://avatars0.githubusercontent.com/u/972498?v=3?s=110" width="110px;" alt="splaer"/><br /><sub><b>splaer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/issues?q=author%3Asplaer" title="Bug reports">🐛</a> <a href="https://github.com/snipe/snipe-it/commits?author=splaer" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/10965027?v=4" width="110px;"/><br /><sub>Ellie</sub>](https://leafedfox.xyz/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeafedFox "Code") | [<img src="https://avatars.githubusercontent.com/u/20960555?v=4" width="110px;"/><br /><sub>GA Stamper</sub>](https://github.com/gastamper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gastamper "Code") | [<img src="https://avatars.githubusercontent.com/u/206553556?v=4" width="110px;"/><br /><sub>Guillaume Lefranc</sub>](https://github.com/gl-pup)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gl-pup "Code") | [<img src="https://avatars.githubusercontent.com/u/733892?v=4" width="110px;"/><br /><sub>Hajo Möller</sub>](https://github.com/dasjoe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dasjoe "Code") | [<img src="https://avatars.githubusercontent.com/u/3420063?v=4" width="110px;"/><br /><sub>Istvan Basa</sub>](https://github.com/pottom)<br />[💻](https://github.com/snipe/snipe-it/commits?author=pottom "Code") | [<img src="https://avatars.githubusercontent.com/u/810824?v=4" width="110px;"/><br /><sub>JJ Asghar</sub>](https://jjasghar.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jjasghar "Code") | [<img src="https://avatars.githubusercontent.com/u/40404495?v=4" width="110px;"/><br /><sub>James E. Msenga</sub>](https://github.com/JemCdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JemCdo "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars.githubusercontent.com/u/6865786?v=4" width="110px;"/><br /><sub>Jan Felix Wiebe</sub>](https://github.com/jfwiebe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jfwiebe "Code") | [<img src="https://avatars.githubusercontent.com/u/43412008?v=4" width="110px;"/><br /><sub>Jo Drexl</sub>](https://www.nfon.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=drexljo "Code") | [<img src="https://avatars.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>Austin Sasko</sub>](https://github.com/austinsasko)<br />[💻](https://github.com/snipe/snipe-it/commits?author=austinsasko "Code") | [<img src="https://avatars.githubusercontent.com/u/4875039?v=4" width="110px;"/><br /><sub>Jasson</sub>](http://jassoncordones.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JassonCordones "Code") | [<img src="https://avatars.githubusercontent.com/u/76069640?v=4" width="110px;"/><br /><sub>Okean</sub>](https://github.com/Tinyblargon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tinyblargon "Code") | [<img src="https://avatars.githubusercontent.com/u/6515064?v=4" width="110px;"/><br /><sub>Alejandro Medrano</sub>](https://www.lst.tfo.upm.es/alejandro-medrano/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=amedranogil "Code") | [<img src="https://avatars.githubusercontent.com/u/58696401?v=4" width="110px;"/><br /><sub>Lukas Kraic</sub>](https://github.com/lukaskraic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukaskraic "Code") |
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.joeferguson.me"><img src="https://avatars1.githubusercontent.com/u/967362?v=3?s=110" width="110px;" alt="Joe Ferguson"/><br /><sub><b>Joe Ferguson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=svpernova09" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/diwanicki"><img src="https://avatars3.githubusercontent.com/u/6108682?v=3?s=110" width="110px;" alt="diwanicki"/><br /><sub><b>diwanicki</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=diwanicki" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=diwanicki" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pakkua80"><img src="https://avatars3.githubusercontent.com/u/2527115?v=3?s=110" width="110px;" alt="Lee Thoong Ching"/><br /><sub><b>Lee Thoong Ching</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=pakkua80" title="Documentation">📖</a> <a href="https://github.com/snipe/snipe-it/commits?author=pakkua80" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://shu.io"><img src="https://avatars1.githubusercontent.com/u/461491?v=3?s=110" width="110px;" alt="Marek Šuppa"/><br /><sub><b>Marek Šuppa</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mrshu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mizar1616"><img src="https://avatars1.githubusercontent.com/u/8693762?v=3?s=110" width="110px;" alt="Juan J. Martinez"/><br /><sub><b>Juan J. Martinez</b></sub></a><br /><a href="#translation-mizar1616" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rrdial"><img src="https://avatars1.githubusercontent.com/u/1458388?v=3?s=110" width="110px;" alt="R Ryan Dial"/><br /><sub><b>R Ryan Dial</b></sub></a><br /><a href="#translation-rrdial" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/burlito"><img src="https://avatars2.githubusercontent.com/u/2871745?v=3?s=110" width="110px;" alt="Andrej Manduch"/><br /><sub><b>Andrej Manduch</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=burlito" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.cordeos.com"><img src="https://avatars0.githubusercontent.com/u/8341172?v=3?s=110" width="110px;" alt="Jay Richards"/><br /><sub><b>Jay Richards</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=technogenus" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://necurity.co.uk"><img src="https://avatars2.githubusercontent.com/u/7295127?v=3?s=110" width="110px;" alt="Alexander Innes"/><br /><sub><b>Alexander Innes</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=leostat" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://buzzedword.codes"><img src="https://avatars2.githubusercontent.com/u/334485?v=3?s=110" width="110px;" alt="Danny Garcia"/><br /><sub><b>Danny Garcia</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=buzzedword" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/archpoint"><img src="https://avatars2.githubusercontent.com/u/366855?v=3?s=110" width="110px;" alt="archpoint"/><br /><sub><b>archpoint</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=archpoint" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jakemcgraw.com"><img src="https://avatars1.githubusercontent.com/u/67991?v=3?s=110" width="110px;" alt="Jake McGraw"/><br /><sub><b>Jake McGraw</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jakemcgraw" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FleischKarussel"><img src="https://avatars1.githubusercontent.com/u/1714374?v=3?s=110" width="110px;" alt="FleischKarussel"/><br /><sub><b>FleischKarussel</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=FleischKarussel" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/feeva"><img src="https://avatars3.githubusercontent.com/u/319644?v=3?s=110" width="110px;" alt="Dylan Yi"/><br /><sub><b>Dylan Yi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=feeva" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://FlashingCursor.com"><img src="https://avatars2.githubusercontent.com/u/857740?v=3?s=110" width="110px;" alt="Gil Rutkowski"/><br /><sub><b>Gil Rutkowski</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=flashingcursor" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.desmondmorris.com"><img src="https://avatars3.githubusercontent.com/u/129360?v=3?s=110" width="110px;" alt="Desmond Morris"/><br /><sub><b>Desmond Morris</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=desmondmorris" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://peelman.us"><img src="https://avatars2.githubusercontent.com/u/52936?v=3?s=110" width="110px;" alt="Nick Peelman"/><br /><sub><b>Nick Peelman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=peelman" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://abrahamvegh.com"><img src="https://avatars0.githubusercontent.com/u/53161?v=3?s=110" width="110px;" alt="Abraham Vegh"/><br /><sub><b>Abraham Vegh</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=abrahamvegh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rashivkp"><img src="https://avatars0.githubusercontent.com/u/2818680?v=3?s=110" width="110px;" alt="Mohamed Rashid"/><br /><sub><b>Mohamed Rashid</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rashivkp" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://hinchk.github.io"><img src="https://avatars3.githubusercontent.com/u/1509456?v=3?s=110" width="110px;" alt="Kasey"/><br /><sub><b>Kasey</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=HinchK" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BrettFagerlund"><img src="https://avatars2.githubusercontent.com/u/10522541?v=3?s=110" width="110px;" alt="Brett"/><br /><sub><b>Brett</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=BrettFagerlund" title="Tests">⚠️</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jasonspriggs.com"><img src="https://avatars2.githubusercontent.com/u/16108587?v=3?s=110" width="110px;" alt="Jason Spriggs"/><br /><sub><b>Jason Spriggs</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jasonspriggs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://n8felton.wordpress.com"><img src="https://avatars2.githubusercontent.com/u/1134568?v=3?s=110" width="110px;" alt="Nate Felton"/><br /><sub><b>Nate Felton</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=n8felton" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://homepages.dcc.ufmg.br/~manassesferreira"><img src="https://avatars2.githubusercontent.com/u/14036694?v=3?s=110" width="110px;" alt="Manasses Ferreira"/><br /><sub><b>Manasses Ferreira</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=manassesferreira" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/steveelwood"><img src="https://avatars0.githubusercontent.com/u/15913949?v=3?s=110" width="110px;" alt="Steve"/><br /><sub><b>Steve</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=steveelwood" title="Tests">⚠️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/matc"><img src="https://avatars1.githubusercontent.com/u/3361683?v=3?s=110" width="110px;" alt="matc"/><br /><sub><b>matc</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=matc" title="Tests">⚠️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.davisracingteam.com"><img src="https://avatars3.githubusercontent.com/u/7405702?v=3?s=110" width="110px;" alt="Cole R. Davis"/><br /><sub><b>Cole R. Davis</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD" title="Tests">⚠️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gibsonjoshua55"><img src="https://avatars2.githubusercontent.com/u/10167681?v=3?s=110" width="110px;" alt="gibsonjoshua55"/><br /><sub><b>gibsonjoshua55</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zwerch"><img src="https://avatars2.githubusercontent.com/u/2809241?v=4?s=110" width="110px;" alt="Robin Temme"/><br /><sub><b>Robin Temme</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=zwerch" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/imanghafoori1"><img src="https://avatars0.githubusercontent.com/u/6961695?v=4?s=110" width="110px;" alt="Iman"/><br /><sub><b>Iman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=imanghafoori1" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/richardhofman6"><img src="https://avatars1.githubusercontent.com/u/6551003?v=4?s=110" width="110px;" alt="Richard Hofman"/><br /><sub><b>Richard Hofman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=richardhofman6" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gizzmojr"><img src="https://avatars0.githubusercontent.com/u/3697569?v=4?s=110" width="110px;" alt="gizzmojr"/><br /><sub><b>gizzmojr</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gizzmojr" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/imjennyli"><img src="https://avatars3.githubusercontent.com/u/404729?v=4?s=110" width="110px;" alt="Jenny Li"/><br /><sub><b>Jenny Li</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=imjennyli" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeoffYoung"><img src="https://avatars0.githubusercontent.com/u/869227?v=4?s=110" width="110px;" alt="Geoff Young"/><br /><sub><b>Geoff Young</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=GeoffYoung" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.elliotblackburn.com"><img src="https://avatars3.githubusercontent.com/u/1068477?v=4?s=110" width="110px;" alt="Elliot Blackburn"/><br /><sub><b>Elliot Blackburn</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=BlueHatbRit" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://andmemasin.eu"><img src="https://avatars1.githubusercontent.com/u/6357451?v=4?s=110" width="110px;" alt="Tõnis Ormisson"/><br /><sub><b>Tõnis Ormisson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=TonisOrmisson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.nicolai-essig.de"><img src="https://avatars0.githubusercontent.com/u/449411?v=4?s=110" width="110px;" alt="Nicolai Essig"/><br /><sub><b>Nicolai Essig</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=thakilla" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/techincolor"><img src="https://avatars1.githubusercontent.com/u/14809698?v=4?s=110" width="110px;" alt="Danielle"/><br /><sub><b>Danielle</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=techincolor" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TheVakman"><img src="https://avatars1.githubusercontent.com/u/18545156?v=4?s=110" width="110px;" alt="Lawrence"/><br /><sub><b>Lawrence</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=TheVakman" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/uknzaeinozpas"><img src="https://avatars1.githubusercontent.com/u/22473767?v=4?s=110" width="110px;" alt="uknzaeinozpas"/><br /><sub><b>uknzaeinozpas</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Gelob"><img src="https://avatars3.githubusercontent.com/u/422752?v=4?s=110" width="110px;" alt="Ryan"/><br /><sub><b>Ryan</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Gelob" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vcordes79"><img src="https://avatars1.githubusercontent.com/u/10672546?v=4?s=110" width="110px;" alt="vcordes79"/><br /><sub><b>vcordes79</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vcordes79" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fordster78"><img src="https://avatars3.githubusercontent.com/u/27958330?v=4?s=110" width="110px;" alt="fordster78"/><br /><sub><b>fordster78</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fordster78" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CronKz"><img src="https://avatars0.githubusercontent.com/u/34064225?v=4?s=110" width="110px;" alt="CronKz"/><br /><sub><b>CronKz</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=CronKz" title="Code">💻</a> <a href="#translation-CronKz" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tdb"><img src="https://avatars1.githubusercontent.com/u/585486?v=4?s=110" width="110px;" alt="Tim Bishop"/><br /><sub><b>Tim Bishop</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tdb" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.seanmcilvenna.com"><img src="https://avatars2.githubusercontent.com/u/5384694?v=4?s=110" width="110px;" alt="Sean McIlvenna"/><br /><sub><b>Sean McIlvenna</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=seanmcilvenna" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cepacs"><img src="https://avatars3.githubusercontent.com/u/36515590?v=4?s=110" width="110px;" alt="cepacs"/><br /><sub><b>cepacs</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/issues?q=author%3Acepacs" title="Bug reports">🐛</a> <a href="https://github.com/snipe/snipe-it/commits?author=cepacs" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lea-mink"><img src="https://avatars2.githubusercontent.com/u/37537300?v=4?s=110" width="110px;" alt="lea-mink"/><br /><sub><b>lea-mink</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=lea-mink" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hannahtinkler"><img src="https://avatars0.githubusercontent.com/u/7140719?v=4?s=110" width="110px;" alt="Hannah Tinkler"/><br /><sub><b>Hannah Tinkler</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=hannahtinkler" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doekman"><img src="https://avatars1.githubusercontent.com/u/1086388?v=4?s=110" width="110px;" alt="Doeke Zanstra"/><br /><sub><b>Doeke Zanstra</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=doekman" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.sdhd.nl/"><img src="https://avatars1.githubusercontent.com/u/4325936?v=4?s=110" width="110px;" alt="Djamon Staal"/><br /><sub><b>Djamon Staal</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=SjamonDaal" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/EarlRamirez"><img src="https://avatars3.githubusercontent.com/u/12306859?v=4?s=110" width="110px;" alt="Earl Ramirez"/><br /><sub><b>Earl Ramirez</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=EarlRamirez" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RichardRay"><img src="https://avatars2.githubusercontent.com/u/8671456?v=4?s=110" width="110px;" alt="Richard Ray Thomas"/><br /><sub><b>Richard Ray Thomas</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=RichardRay" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.taisun.io/"><img src="https://avatars3.githubusercontent.com/u/1852688?v=4?s=110" width="110px;" alt="Ryan Kuba"/><br /><sub><b>Ryan Kuba</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=thelamer" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ParadoxGuitarist"><img src="https://avatars1.githubusercontent.com/u/6751928?v=4?s=110" width="110px;" alt="Brian Monroe"/><br /><sub><b>Brian Monroe</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ParadoxGuitarist" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/plexorama"><img src="https://avatars1.githubusercontent.com/u/605167?v=4?s=110" width="110px;" alt="plexorama"/><br /><sub><b>plexorama</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=plexorama" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://tilldeeke.de"><img src="https://avatars2.githubusercontent.com/u/1795149?v=4?s=110" width="110px;" alt="Till Deeke"/><br /><sub><b>Till Deeke</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tilldeeke" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/5quirrel"><img src="https://avatars0.githubusercontent.com/u/12634129?v=4?s=110" width="110px;" alt="5quirrel"/><br /><sub><b>5quirrel</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=5quirrel" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jasonlshelton"><img src="https://avatars1.githubusercontent.com/u/13071957?v=4?s=110" width="110px;" alt="Jason"/><br /><sub><b>Jason</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jasonlshelton" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chemfy"><img src="https://avatars3.githubusercontent.com/u/7128321?v=4?s=110" width="110px;" alt="Antti"/><br /><sub><b>Antti</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chemfy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DeusMaximus"><img src="https://avatars3.githubusercontent.com/u/10080364?v=4?s=110" width="110px;" alt="DeusMaximus"/><br /><sub><b>DeusMaximus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=DeusMaximus" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/A-ROYAL"><img src="https://avatars2.githubusercontent.com/u/16384611?v=4?s=110" width="110px;" alt="a-royal"/><br /><sub><b>a-royal</b></sub></a><br /><a href="#translation-A-ROYAL" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/albertoaldrigo"><img src="https://avatars0.githubusercontent.com/u/5358208?v=4?s=110" width="110px;" alt="Alberto Aldrigo"/><br /><sub><b>Alberto Aldrigo</b></sub></a><br /><a href="#translation-albertoaldrigo" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://alex.stanev.org/blog"><img src="https://avatars0.githubusercontent.com/u/1412342?v=4?s=110" width="110px;" alt="Alex Stanev"/><br /><sub><b>Alex Stanev</b></sub></a><br /><a href="#translation-RealEnder" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://devel.itsolution2.de"><img src="https://avatars0.githubusercontent.com/u/177295?v=4?s=110" width="110px;" alt="Andreas Rehm"/><br /><sub><b>Andreas Rehm</b></sub></a><br /><a href="#translation-sirrus" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xelan"><img src="https://avatars0.githubusercontent.com/u/5080535?v=4?s=110" width="110px;" alt="Andreas Erhard"/><br /><sub><b>Andreas Erhard</b></sub></a><br /><a href="#translation-xelan" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/angeldeejay"><img src="https://avatars2.githubusercontent.com/u/142350?v=4?s=110" width="110px;" alt="Andrés Vanegas Jiménez"/><br /><sub><b>Andrés Vanegas Jiménez</b></sub></a><br /><a href="#translation-angeldeejay" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aschiavon91"><img src="https://avatars0.githubusercontent.com/u/3910403?v=4?s=110" width="110px;" alt="Antonio Schiavon"/><br /><sub><b>Antonio Schiavon</b></sub></a><br /><a href="#translation-aschiavon91" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benunter"><img src="https://avatars0.githubusercontent.com/u/10464547?v=4?s=110" width="110px;" alt="benunter"/><br /><sub><b>benunter</b></sub></a><br /><a href="#translation-benunter" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://catweb24.pl"><img src="https://avatars1.githubusercontent.com/u/5038647?v=4?s=110" width="110px;" alt="Borys Żmuda"/><br /><sub><b>Borys Żmuda</b></sub></a><br /><a href="#translation-rudashi" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chibacityblues"><img src="https://avatars0.githubusercontent.com/u/5539359?v=4?s=110" width="110px;" alt="chibacityblues"/><br /><sub><b>chibacityblues</b></sub></a><br /><a href="#translation-chibacityblues" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cwlin0416"><img src="https://avatars1.githubusercontent.com/u/1954830?v=4?s=110" width="110px;" alt="Chien Wei Lin"/><br /><sub><b>Chien Wei Lin</b></sub></a><br /><a href="#translation-cwlin0416" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Againstreality"><img src="https://avatars3.githubusercontent.com/u/11700533?v=4?s=110" width="110px;" alt="Christian Schuster"/><br /><sub><b>Christian Schuster</b></sub></a><br /><a href="#translation-Againstreality" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://chriss.webhostid.com"><img src="https://avatars1.githubusercontent.com/u/4308704?v=4?s=110" width="110px;" alt="Christian Stefanus"/><br /><sub><b>Christian Stefanus</b></sub></a><br /><a href="#translation-kopi-item" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://wxcafe.net"><img src="https://avatars3.githubusercontent.com/u/3009327?v=4?s=110" width="110px;" alt="wxcafé"/><br /><sub><b>wxcafé</b></sub></a><br /><a href="#translation-wxcafe" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dpyroc"><img src="https://avatars3.githubusercontent.com/u/35761525?v=4?s=110" width="110px;" alt="dpyroc"/><br /><sub><b>dpyroc</b></sub></a><br /><a href="#translation-dpyroc" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.friedlmaier.net"><img src="https://avatars1.githubusercontent.com/u/2153639?v=4?s=110" width="110px;" alt="Daniel Friedlmaier"/><br /><sub><b>Daniel Friedlmaier</b></sub></a><br /><a href="#translation-da-friedl" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/danielheene"><img src="https://avatars1.githubusercontent.com/u/2947640?v=4?s=110" width="110px;" alt="Daniel Heene"/><br /><sub><b>Daniel Heene</b></sub></a><br /><a href="#translation-danielheene" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/danielcb"><img src="https://avatars3.githubusercontent.com/u/319022?v=4?s=110" width="110px;" alt="danielcb"/><br /><sub><b>danielcb</b></sub></a><br /><a href="#translation-danielcb" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dominiksenti"><img src="https://avatars3.githubusercontent.com/u/15846537?v=4?s=110" width="110px;" alt="Dominik Senti"/><br /><sub><b>Dominik Senti</b></sub></a><br /><a href="#translation-dominiksenti" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.konectik.com"><img src="https://avatars0.githubusercontent.com/u/25570954?v=4?s=110" width="110px;" alt="Eric Gautheron"/><br /><sub><b>Eric Gautheron</b></sub></a><br /><a href="#translation-EpixFr" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://erlpil.com"><img src="https://avatars1.githubusercontent.com/u/5732623?v=4?s=110" width="110px;" alt="Erlend Pilø"/><br /><sub><b>Erlend Pilø</b></sub></a><br /><a href="#translation-Erlpil" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://fabio.technology"><img src="https://avatars0.githubusercontent.com/u/541832?v=4?s=110" width="110px;" alt="Fabio Rapposelli"/><br /><sub><b>Fabio Rapposelli</b></sub></a><br /><a href="#translation-frapposelli" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fgbs"><img src="https://avatars2.githubusercontent.com/u/3605240?v=4?s=110" width="110px;" alt="Felipe Barros"/><br /><sub><b>Felipe Barros</b></sub></a><br /><a href="#translation-fgbs" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/possebon"><img src="https://avatars0.githubusercontent.com/u/257745?v=4?s=110" width="110px;" alt="Fernando Possebon"/><br /><sub><b>Fernando Possebon</b></sub></a><br /><a href="#translation-possebon" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gdraque"><img src="https://avatars3.githubusercontent.com/u/2540832?v=4?s=110" width="110px;" alt="gdraque"/><br /><sub><b>gdraque</b></sub></a><br /><a href="#translation-gdraque" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/georgwallisch"><img src="https://avatars0.githubusercontent.com/u/23440381?v=4?s=110" width="110px;" alt="Georg Wallisch"/><br /><sub><b>Georg Wallisch</b></sub></a><br /><a href="#translation-georgwallisch" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jgroblesr85"><img src="https://avatars1.githubusercontent.com/u/9852832?v=4?s=110" width="110px;" alt="Gerardo Robles"/><br /><sub><b>Gerardo Robles</b></sub></a><br /><a href="#translation-jgroblesr85" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://t.me/Gluek"><img src="https://avatars2.githubusercontent.com/u/11082640?v=4?s=110" width="110px;" alt="Gluek"/><br /><sub><b>Gluek</b></sub></a><br /><a href="#translation-mrgluek" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AdnanAbuShahad"><img src="https://avatars0.githubusercontent.com/u/6847946?v=4?s=110" width="110px;" alt="AdnanAbuShahad"/><br /><sub><b>AdnanAbuShahad</b></sub></a><br /><a href="#translation-AdnanAbuShahad" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hafidzi.my"><img src="https://avatars1.githubusercontent.com/u/3580608?v=4?s=110" width="110px;" alt="Hafidzi My"/><br /><sub><b>Hafidzi My</b></sub></a><br /><a href="#translation-hafidzi" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fofwisdom"><img src="https://avatars2.githubusercontent.com/u/205521?v=4?s=110" width="110px;" alt="Harim Park"/><br /><sub><b>Harim Park</b></sub></a><br /><a href="#translation-fofwisdom" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.kentsson.se"><img src="https://avatars2.githubusercontent.com/u/3333841?v=4?s=110" width="110px;" alt="Henrik Kentsson"/><br /><sub><b>Henrik Kentsson</b></sub></a><br /><a href="#translation-Kentsson" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/husnulyaqien"><img src="https://avatars0.githubusercontent.com/u/36551034?v=4?s=110" width="110px;" alt="Husnul Yaqien"/><br /><sub><b>Husnul Yaqien</b></sub></a><br /><a href="#translation-husnulyaqien" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://abaalkhail.org"><img src="https://avatars1.githubusercontent.com/u/2372747?v=4?s=110" width="110px;" alt="Ibrahim"/><br /><sub><b>Ibrahim</b></sub></a><br /><a href="#translation-abaalkh" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/igolman"><img src="https://avatars0.githubusercontent.com/u/1389334?v=4?s=110" width="110px;" alt="igolman"/><br /><sub><b>igolman</b></sub></a><br /><a href="#translation-igolman" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/itangiang"><img src="https://avatars1.githubusercontent.com/u/3257070?v=4?s=110" width="110px;" alt="itangiang"/><br /><sub><b>itangiang</b></sub></a><br /><a href="#translation-itangiang" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jarby1211"><img src="https://avatars2.githubusercontent.com/u/14814254?v=4?s=110" width="110px;" alt="jarby1211"/><br /><sub><b>jarby1211</b></sub></a><br /><a href="#translation-jarby1211" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jwillker.com"><img src="https://avatars3.githubusercontent.com/u/6719357?v=4?s=110" width="110px;" alt="Jhonn Willker"/><br /><sub><b>Jhonn Willker</b></sub></a><br /><a href="#translation-JohnWillker" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/joxelito94"><img src="https://avatars2.githubusercontent.com/u/10983635?v=4?s=110" width="110px;" alt="Jose"/><br /><sub><b>Jose</b></sub></a><br /><a href="#translation-joxelito94" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/laopangzi"><img src="https://avatars0.githubusercontent.com/u/5206122?v=4?s=110" width="110px;" alt="laopangzi"/><br /><sub><b>laopangzi</b></sub></a><br /><a href="#translation-laopangzi" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://usrportage.de"><img src="https://avatars2.githubusercontent.com/u/79707?v=4?s=110" width="110px;" alt="Lars Strojny"/><br /><sub><b>Lars Strojny</b></sub></a><br /><a href="#translation-lstrojny" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/marcosbl"><img src="https://avatars0.githubusercontent.com/u/389801?v=4?s=110" width="110px;" alt="MarcosBL"/><br /><sub><b>MarcosBL</b></sub></a><br /><a href="#translation-MarcosBL" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mariejoyacajes"><img src="https://avatars3.githubusercontent.com/u/35664606?v=4?s=110" width="110px;" alt="marie joy cajes"/><br /><sub><b>marie joy cajes</b></sub></a><br /><a href="#translation-mariejoyacajes" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.markjohansen.dk"><img src="https://avatars2.githubusercontent.com/u/3052816?v=4?s=110" width="110px;" alt="Mark S. Johansen"/><br /><sub><b>Mark S. Johansen</b></sub></a><br /><a href="#translation-msjohansen" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://martinstub.dk"><img src="https://avatars2.githubusercontent.com/u/982885?v=4?s=110" width="110px;" alt="Martin Stub"/><br /><sub><b>Martin Stub</b></sub></a><br /><a href="#translation-stubben" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/meyerf99"><img src="https://avatars2.githubusercontent.com/u/28959963?v=4?s=110" width="110px;" alt="Meyer Flavio"/><br /><sub><b>Meyer Flavio</b></sub></a><br /><a href="#translation-meyerf99" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MicaelRodrigues"><img src="https://avatars3.githubusercontent.com/u/796443?v=4?s=110" width="110px;" alt="Micael Rodrigues"/><br /><sub><b>Micael Rodrigues</b></sub></a><br /><a href="#translation-MicaelRodrigues" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://rubixy.com/"><img src="https://avatars0.githubusercontent.com/u/10481331?v=4?s=110" width="110px;" alt="Mikael Rasmussen"/><br /><sub><b>Mikael Rasmussen</b></sub></a><br /><a href="#translation-mikaelssen" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IxFail"><img src="https://avatars1.githubusercontent.com/u/1544552?v=4?s=110" width="110px;" alt="IxFail"/><br /><sub><b>IxFail</b></sub></a><br /><a href="#translation-IxFail" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.mohammedfota.com"><img src="https://avatars3.githubusercontent.com/u/18483118?v=4?s=110" width="110px;" alt="Mohammed Fota"/><br /><sub><b>Mohammed Fota</b></sub></a><br /><a href="#translation-MohammedFota" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/omego"><img src="https://avatars0.githubusercontent.com/u/227080?v=4?s=110" width="110px;" alt="Moayad Alserihi"/><br /><sub><b>Moayad Alserihi</b></sub></a><br /><a href="#translation-omego" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/saymd"><img src="https://avatars0.githubusercontent.com/u/1680266?v=4?s=110" width="110px;" alt="saymd"/><br /><sub><b>saymd</b></sub></a><br /><a href="#translation-saymd" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nordsken.se"><img src="https://avatars0.githubusercontent.com/u/1826808?v=4?s=110" width="110px;" alt="Patrik Larsson"/><br /><sub><b>Patrik Larsson</b></sub></a><br /><a href="#translation-pooot" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/drcryo"><img src="https://avatars1.githubusercontent.com/u/20584746?v=4?s=110" width="110px;" alt="drcryo"/><br /><sub><b>drcryo</b></sub></a><br /><a href="#translation-drcryo" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pawel1615"><img src="https://avatars1.githubusercontent.com/u/19408004?v=4?s=110" width="110px;" alt="pawel1615"/><br /><sub><b>pawel1615</b></sub></a><br /><a href="#translation-pawel1615" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bodrovics"><img src="https://avatars2.githubusercontent.com/u/23340468?v=4?s=110" width="110px;" alt="bodrovics"/><br /><sub><b>bodrovics</b></sub></a><br /><a href="#translation-bodrovics" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/priatna"><img src="https://avatars0.githubusercontent.com/u/3257654?v=4?s=110" width="110px;" alt="priatna"/><br /><sub><b>priatna</b></sub></a><br /><a href="#translation-priatna" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://amayume.net"><img src="https://avatars1.githubusercontent.com/u/5358374?v=4?s=110" width="110px;" alt="Fan Jiang"/><br /><sub><b>Fan Jiang</b></sub></a><br /><a href="#translation-ProfFan" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ragnarcx"><img src="https://avatars1.githubusercontent.com/u/22555451?v=4?s=110" width="110px;" alt="ragnarcx"/><br /><sub><b>ragnarcx</b></sub></a><br /><a href="#translation-ragnarcx" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.reinvanhaaren.nl/"><img src="https://avatars2.githubusercontent.com/u/18654582?v=4?s=110" width="110px;" alt="Rein van Haaren"/><br /><sub><b>Rein van Haaren</b></sub></a><br /><a href="#translation-reinvanhaaren" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://dheche.songolimo.net"><img src="https://avatars1.githubusercontent.com/u/386672?v=4?s=110" width="110px;" alt="Teguh Dwicaksana"/><br /><sub><b>Teguh Dwicaksana</b></sub></a><br /><a href="#translation-dheche" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FRaccie"><img src="https://avatars2.githubusercontent.com/u/2572552?v=4?s=110" width="110px;" alt="fraccie"/><br /><sub><b>fraccie</b></sub></a><br /><a href="#translation-FRaccie" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vinzruzell"><img src="https://avatars0.githubusercontent.com/u/35182720?v=4?s=110" width="110px;" alt="vinzruzell"/><br /><sub><b>vinzruzell</b></sub></a><br /><a href="#translation-vinzruzell" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://kevinaustin.com"><img src="https://avatars1.githubusercontent.com/u/7883603?v=4?s=110" width="110px;" alt="Kevin Austin"/><br /><sub><b>Kevin Austin</b></sub></a><br /><a href="#translation-vipsystem" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://azuraweb.xyz"><img src="https://avatars3.githubusercontent.com/u/3861828?v=4?s=110" width="110px;" alt="Wira Sandy"/><br /><sub><b>Wira Sandy</b></sub></a><br /><a href="#translation-wira-sandy" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GrayHoax"><img src="https://avatars2.githubusercontent.com/u/8663789?v=4?s=110" width="110px;" alt="Илья"/><br /><sub><b>Илья</b></sub></a><br /><a href="#translation-GrayHoax" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/godusevpn"><img src="https://avatars3.githubusercontent.com/u/30119111?v=4?s=110" width="110px;" alt="GodUseVPN"/><br /><sub><b>GodUseVPN</b></sub></a><br /><a href="#translation-godusevpn" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/EngrZhou"><img src="https://avatars1.githubusercontent.com/u/745576?v=4?s=110" width="110px;" alt="周周"/><br /><sub><b>周周</b></sub></a><br /><a href="#translation-EngrZhou" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/takuy"><img src="https://avatars3.githubusercontent.com/u/1631095?v=4?s=110" width="110px;" alt="Sam"/><br /><sub><b>Sam</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=takuy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.illisian.com.au"><img src="https://avatars1.githubusercontent.com/u/264022?v=4?s=110" width="110px;" alt="Azerothian"/><br /><sub><b>Azerothian</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Azerothian" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://macfoo.wordpress.com/"><img src="https://avatars1.githubusercontent.com/u/4930051?v=4?s=110" width="110px;" alt="Wes Hulette"/><br /><sub><b>Wes Hulette</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jwhulette" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/patrict"><img src="https://avatars0.githubusercontent.com/u/8134591?v=4?s=110" width="110px;" alt="patrict"/><br /><sub><b>patrict</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=patrict" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VELIKII-DIVAN"><img src="https://avatars3.githubusercontent.com/u/2611616?v=4?s=110" width="110px;" alt="Dmitriy Minaev"/><br /><sub><b>Dmitriy Minaev</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/liquidhorse"><img src="https://avatars0.githubusercontent.com/u/5132245?v=4?s=110" width="110px;" alt="liquidhorse"/><br /><sub><b>liquidhorse</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=liquidhorse" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://seld.be/"><img src="https://avatars1.githubusercontent.com/u/183678?v=4?s=110" width="110px;" alt="Jordi Boggiano"/><br /><sub><b>Jordi Boggiano</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Seldaek" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/inietov"><img src="https://avatars0.githubusercontent.com/u/653557?v=4?s=110" width="110px;" alt="Ivan Nieto"/><br /><sub><b>Ivan Nieto</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=inietov" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benrubson"><img src="https://avatars2.githubusercontent.com/u/6764151?v=4?s=110" width="110px;" alt="Ben RUBSON"/><br /><sub><b>Ben RUBSON</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=benrubson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NMathar"><img src="https://avatars2.githubusercontent.com/u/8554558?v=4?s=110" width="110px;" alt="NMathar"/><br /><sub><b>NMathar</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=NMathar" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smb"><img src="https://avatars1.githubusercontent.com/u/139566?v=4?s=110" width="110px;" alt="Steffen"/><br /><sub><b>Steffen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=smb" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Sxderp"><img src="https://avatars0.githubusercontent.com/u/6609453?v=4?s=110" width="110px;" alt="Sxderp"/><br /><sub><b>Sxderp</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Sxderp" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fanta8897"><img src="https://avatars1.githubusercontent.com/u/4807843?v=4?s=110" width="110px;" alt="fanta8897"/><br /><sub><b>fanta8897</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fanta8897" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://andreybolonin.com/phpconsulting/"><img src="https://avatars2.githubusercontent.com/u/2576509?v=4?s=110" width="110px;" alt="Andrey Bolonin"/><br /><sub><b>Andrey Bolonin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=andreybolonin" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.shinayoshi.net/"><img src="https://avatars3.githubusercontent.com/u/2173307?v=4?s=110" width="110px;" alt="shinayoshi"/><br /><sub><b>shinayoshi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=shinayoshi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/reuser"><img src="https://avatars3.githubusercontent.com/u/2130159?v=4?s=110" width="110px;" alt="Hubert"/><br /><sub><b>Hubert</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=reuser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://brashear.me"><img src="https://avatars0.githubusercontent.com/u/6865789?v=4?s=110" width="110px;" alt="KeenRivals"/><br /><sub><b>KeenRivals</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=KeenRivals" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/omyno"><img src="https://avatars3.githubusercontent.com/u/2902513?v=4?s=110" width="110px;" alt="omyno"/><br /><sub><b>omyno</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=omyno" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jackka"><img src="https://avatars1.githubusercontent.com/u/6271335?v=4?s=110" width="110px;" alt="Evgeny"/><br /><sub><b>Evgeny</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jackka" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://digitalist.se"><img src="https://avatars2.githubusercontent.com/u/1169963?v=4?s=110" width="110px;" alt="Colin Campbell"/><br /><sub><b>Colin Campbell</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=colin-campbell" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lubo"><img src="https://avatars3.githubusercontent.com/u/2872098?v=4?s=110" width="110px;" alt="Ľubomír Kučera"/><br /><sub><b>Ľubomír Kučera</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=lubo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.sourceguru.net"><img src="https://avatars3.githubusercontent.com/u/570639?v=4?s=110" width="110px;" alt="Martin Meredith"/><br /><sub><b>Martin Meredith</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Mezzle" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/timothyfarmer"><img src="https://avatars1.githubusercontent.com/u/7632599?v=4?s=110" width="110px;" alt="Tim Farmer"/><br /><sub><b>Tim Farmer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=timothyfarmer" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mskrip"><img src="https://avatars0.githubusercontent.com/u/17459600?v=4?s=110" width="110px;" alt="Marián Skrip"/><br /><sub><b>Marián Skrip</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mskrip" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Godmartinz"><img src="https://avatars2.githubusercontent.com/u/47435081?v=4?s=110" width="110px;" alt="Godfrey Martinez"/><br /><sub><b>Godfrey Martinez</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Godmartinz" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bigtreeEdo"><img src="https://avatars1.githubusercontent.com/u/2075128?v=4?s=110" width="110px;" alt="bigtreeEdo"/><br /><sub><b>bigtreeEdo</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bigtreeEdo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://colinmcneil.me/"><img src="https://avatars0.githubusercontent.com/u/5000430?v=4?s=110" width="110px;" alt="Colin McNeil"/><br /><sub><b>Colin McNeil</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ColinMcNeil" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JoKneeMo"><img src="https://avatars0.githubusercontent.com/u/421625?v=4?s=110" width="110px;" alt="JoKneeMo"/><br /><sub><b>JoKneeMo</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=JoKneeMo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.redbridge.se"><img src="https://avatars0.githubusercontent.com/u/54849013?v=4?s=110" width="110px;" alt="Joshi"/><br /><sub><b>Joshi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=joshi-redbridge" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/anthonypburns"><img src="https://avatars2.githubusercontent.com/u/15731458?v=4?s=110" width="110px;" alt="Anthony Burns"/><br /><sub><b>Anthony Burns</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=anthonypburns" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/johnson-yi"><img src="https://avatars1.githubusercontent.com/u/63399474?v=4?s=110" width="110px;" alt="johnson-yi"/><br /><sub><b>johnson-yi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=johnson-yi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://tangentmc.net"><img src="https://avatars1.githubusercontent.com/u/1862720?v=4?s=110" width="110px;" alt="Sanjay Govind"/><br /><sub><b>Sanjay Govind</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sanjay900" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://peter.upfold.org.uk/"><img src="https://avatars0.githubusercontent.com/u/1255375?v=4?s=110" width="110px;" alt="Peter Upfold"/><br /><sub><b>Peter Upfold</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PeterUpfold" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jbiel"><img src="https://avatars2.githubusercontent.com/u/961717?v=4?s=110" width="110px;" alt="Jared Biel"/><br /><sub><b>Jared Biel</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jbiel" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dampfklon"><img src="https://avatars1.githubusercontent.com/u/1733625?v=4?s=110" width="110px;" alt="Dampfklon"/><br /><sub><b>Dampfklon</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dampfklon" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://communityclosing.com"><img src="https://avatars2.githubusercontent.com/u/52973156?v=4?s=110" width="110px;" alt="Charles Hamilton"/><br /><sub><b>Charles Hamilton</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chamilton-ccn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/giannello"><img src="https://avatars.githubusercontent.com/u/551789?v=4?s=110" width="110px;" alt="Giuseppe Iannello"/><br /><sub><b>Giuseppe Iannello</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=giannello" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.peterdavehello.org/"><img src="https://avatars.githubusercontent.com/u/3691490?v=4?s=110" width="110px;" alt="Peter Dave Hello"/><br /><sub><b>Peter Dave Hello</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PeterDaveHello" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sigmoidal"><img src="https://avatars.githubusercontent.com/u/6106332?v=4?s=110" width="110px;" alt="sigmoidal"/><br /><sub><b>sigmoidal</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sigmoidal" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/phenixdotnet"><img src="https://avatars.githubusercontent.com/u/2082554?v=4?s=110" width="110px;" alt="Vincent Lainé"/><br /><sub><b>Vincent Lainé</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=phenixdotnet" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.lucas-pless.com"><img src="https://avatars.githubusercontent.com/u/1943040?v=4?s=110" width="110px;" alt="Lucas Pleß"/><br /><sub><b>Lucas Pleß</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=derlucas" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/iansltx"><img src="https://avatars.githubusercontent.com/u/472804?v=4?s=110" width="110px;" alt="Ian Littman"/><br /><sub><b>Ian Littman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=iansltx" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PauloLuna"><img src="https://avatars.githubusercontent.com/u/3519029?v=4?s=110" width="110px;" alt="João Paulo"/><br /><sub><b>João Paulo</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PauloLuna" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ThoBur"><img src="https://avatars.githubusercontent.com/u/70443365?v=4?s=110" width="110px;" alt="ThoBur"/><br /><sub><b>ThoBur</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ThoBur" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://phpprofi.ru/"><img src="https://avatars.githubusercontent.com/u/1972329?v=4?s=110" width="110px;" alt="Alexander Chibrikin"/><br /><sub><b>Alexander Chibrikin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=alek13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/winstan"><img src="https://avatars.githubusercontent.com/u/438332?v=4?s=110" width="110px;" alt="Anthony Winstanley"/><br /><sub><b>Anthony Winstanley</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=winstan" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fashberg"><img src="https://avatars.githubusercontent.com/u/3075214?v=4?s=110" width="110px;" alt="Folke"/><br /><sub><b>Folke</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fashberg" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benwa"><img src="https://avatars.githubusercontent.com/u/1351571?v=4?s=110" width="110px;" alt="Bennett Blodinger"/><br /><sub><b>Bennett Blodinger</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=benwa" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nmc.dev"><img src="https://avatars.githubusercontent.com/u/2974631?v=4?s=110" width="110px;" alt="NMC"/><br /><sub><b>NMC</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ncareau" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andres-baller"><img src="https://avatars.githubusercontent.com/u/52182449?v=4?s=110" width="110px;" alt="andres-baller"/><br /><sub><b>andres-baller</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=andres-baller" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sean-borg"><img src="https://avatars.githubusercontent.com/u/67109348?v=4?s=110" width="110px;" alt="sean-borg"/><br /><sub><b>sean-borg</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sean-borg" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/EDVLeer"><img src="https://avatars.githubusercontent.com/u/32170051?v=4?s=110" width="110px;" alt="EDVLeer"/><br /><sub><b>EDVLeer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=EDVLeer" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kurokat"><img src="https://avatars.githubusercontent.com/u/23075196?v=4?s=110" width="110px;" alt="Kurokat"/><br /><sub><b>Kurokat</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Kurokat" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.kevinkoellmann.de"><img src="https://avatars.githubusercontent.com/u/915514?v=4?s=110" width="110px;" alt="Kevin Köllmann"/><br /><sub><b>Kevin Köllmann</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=koelle25" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sw-mreyes"><img src="https://avatars.githubusercontent.com/u/49025941?v=4?s=110" width="110px;" alt="sw-mreyes"/><br /><sub><b>sw-mreyes</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sw-mreyes" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://pittet.ca"><img src="https://avatars.githubusercontent.com/u/70129?v=4?s=110" width="110px;" alt="Joel Pittet"/><br /><sub><b>Joel Pittet</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=joelpittet" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://elyscape.com"><img src="https://avatars.githubusercontent.com/u/792695?v=4?s=110" width="110px;" alt="Eli Young"/><br /><sub><b>Eli Young</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=elyscape" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/raelldottin"><img src="https://avatars.githubusercontent.com/u/317015?v=4?s=110" width="110px;" alt="Raell Dottin"/><br /><sub><b>Raell Dottin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=raelldottin" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/misilot"><img src="https://avatars.githubusercontent.com/u/1446856?v=4?s=110" width="110px;" alt="Tom Misilo"/><br /><sub><b>Tom Misilo</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=misilot" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://david.davenne.be"><img src="https://avatars.githubusercontent.com/u/4496300?v=4?s=110" width="110px;" alt="David Davenne"/><br /><sub><b>David Davenne</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=JuustoMestari" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://markstenglein.com"><img src="https://avatars.githubusercontent.com/u/9255772?v=4?s=110" width="110px;" alt="Mark Stenglein"/><br /><sub><b>Mark Stenglein</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ocelotsloth" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ajsy"><img src="https://avatars.githubusercontent.com/u/35658596?v=4?s=110" width="110px;" alt="ajsy"/><br /><sub><b>ajsy</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ajsy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/t3easy"><img src="https://avatars.githubusercontent.com/u/3628035?v=4?s=110" width="110px;" alt="Jan Kiesewetter"/><br /><sub><b>Jan Kiesewetter</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=t3easy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tetrachloromethane250"><img src="https://avatars.githubusercontent.com/u/79449630?v=4?s=110" width="110px;" alt="Tetrachloromethane250"/><br /><sub><b>Tetrachloromethane250</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.kajes.se/"><img src="https://avatars.githubusercontent.com/u/22004482?v=4?s=110" width="110px;" alt="Lars Kajes"/><br /><sub><b>Lars Kajes</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=kajes" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Joly0"><img src="https://avatars.githubusercontent.com/u/13993216?v=4?s=110" width="110px;" alt="Joly0"/><br /><sub><b>Joly0</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Joly0" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/limeless"><img src="https://avatars.githubusercontent.com/u/1501022?v=4?s=110" width="110px;" alt="theburger"/><br /><sub><b>theburger</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=limeless" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/deivishome"><img src="https://avatars.githubusercontent.com/u/36065681?v=4?s=110" width="110px;" alt="David Valin Alonso"/><br /><sub><b>David Valin Alonso</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=deivishome" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andreaci"><img src="https://avatars.githubusercontent.com/u/8290389?v=4?s=110" width="110px;" alt="andreaci"/><br /><sub><b>andreaci</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=andreaci" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jellesebreghts.be"><img src="https://avatars.githubusercontent.com/u/1828542?v=4?s=110" width="110px;" alt="Jelle Sebreghts"/><br /><sub><b>Jelle Sebreghts</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Jelle-S" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Skywalker-11"><img src="https://avatars.githubusercontent.com/u/11180862?v=4?s=110" width="110px;" alt="Michael Pietsch"/><br /><sub><b>Michael Pietsch</b></sub></a><br /></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sh1hab"><img src="https://avatars.githubusercontent.com/u/22068886?v=4?s=110" width="110px;" alt="Masudul Haque Shihab"/><br /><sub><b>Masudul Haque Shihab</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sh1hab" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.freedomdive.com/"><img src="https://avatars.githubusercontent.com/u/16099942?v=4?s=110" width="110px;" alt="Supapong Areeprasertkul"/><br /><sub><b>Supapong Areeprasertkul</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=zybersup" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/psarossy"><img src="https://avatars.githubusercontent.com/u/207358?v=4?s=110" width="110px;" alt="Peter Sarossy"/><br /><sub><b>Peter Sarossy</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=psarossy" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nepella"><img src="https://avatars.githubusercontent.com/u/11823649?v=4?s=110" width="110px;" alt="Renee Margaret McConahy"/><br /><sub><b>Renee Margaret McConahy</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nepella" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JohnnyPicnic"><img src="https://avatars.githubusercontent.com/u/5553884?v=4?s=110" width="110px;" alt="JohnnyPicnic"/><br /><sub><b>JohnnyPicnic</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/markbrule"><img src="https://avatars.githubusercontent.com/u/8799594?v=4?s=110" width="110px;" alt="markbrule"/><br /><sub><b>markbrule</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=markbrule" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikecmpbll"><img src="https://avatars.githubusercontent.com/u/1962801?v=4?s=110" width="110px;" alt="Mike Campbell"/><br /><sub><b>Mike Campbell</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mikecmpbll" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tbrconnect"><img src="https://avatars.githubusercontent.com/u/11973217?v=4?s=110" width="110px;" alt="tbrconnect"/><br /><sub><b>tbrconnect</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tbrconnect" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kcoyo"><img src="https://avatars.githubusercontent.com/u/12447225?v=4?s=110" width="110px;" alt="kcoyo"/><br /><sub><b>kcoyo</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=kcoyo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://travismiller.com/"><img src="https://avatars.githubusercontent.com/u/494017?v=4?s=110" width="110px;" alt="Travis Miller"/><br /><sub><b>Travis Miller</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=travismiller" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Delta5"><img src="https://avatars.githubusercontent.com/u/1975640?v=4?s=110" width="110px;" alt="Evan Taylor"/><br /><sub><b>Evan Taylor</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Delta5" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PetriAsi"><img src="https://avatars.githubusercontent.com/u/8735148?v=4?s=110" width="110px;" alt="Petri Asikainen"/><br /><sub><b>Petri Asikainen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PetriAsi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/derdeagle"><img src="https://avatars.githubusercontent.com/u/11424540?v=4?s=110" width="110px;" alt="derdeagle"/><br /><sub><b>derdeagle</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=derdeagle" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://wh0rd.org/"><img src="https://avatars.githubusercontent.com/u/176950?v=4?s=110" width="110px;" alt="Mike Frysinger"/><br /><sub><b>Mike Frysinger</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vapier" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AL4AL"><img src="https://avatars.githubusercontent.com/u/22044358?v=4?s=110" width="110px;" alt="ALPHA"/><br /><sub><b>ALPHA</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=AL4AL" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.ifern.de"><img src="https://avatars.githubusercontent.com/u/1042587?v=4?s=110" width="110px;" alt="FliegenKLATSCH"/><br /><sub><b>FliegenKLATSCH</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jerm"><img src="https://avatars.githubusercontent.com/u/442138?v=4?s=110" width="110px;" alt="Jeremy Price"/><br /><sub><b>Jeremy Price</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jerm" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Toreg87"><img src="https://avatars.githubusercontent.com/u/84392209?v=4?s=110" width="110px;" alt="Toreg87"/><br /><sub><b>Toreg87</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Toreg87" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Computroniks"><img src="https://avatars.githubusercontent.com/u/67638596?v=4?s=110" width="110px;" alt="Matthew Nickson"/><br /><sub><b>Matthew Nickson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Computroniks" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://jethron.id.au"><img src="https://avatars.githubusercontent.com/u/1646397?v=4?s=110" width="110px;" alt="Jethro Nederhof"/><br /><sub><b>Jethro Nederhof</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jethron" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/01ste02"><img src="https://avatars.githubusercontent.com/u/23289826?v=4?s=110" width="110px;" alt="Oskar Stenberg"/><br /><sub><b>Oskar Stenberg</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=01ste02" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Robert-Azelis"><img src="https://avatars.githubusercontent.com/u/82208283?v=4?s=110" width="110px;" alt="Robert-Azelis"/><br /><sub><b>Robert-Azelis</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Robert-Azelis" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alwism"><img src="https://avatars.githubusercontent.com/u/60648387?v=4?s=110" width="110px;" alt="Alexander William Smith"/><br /><sub><b>Alexander William Smith</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=alwism" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.leitwerk.de/"><img src="https://avatars.githubusercontent.com/u/24418301?v=4?s=110" width="110px;" alt="LEITWERK AG"/><br /><sub><b>LEITWERK AG</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=leitwerk-ag" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.aboutcher.co.uk"><img src="https://avatars.githubusercontent.com/u/1911435?v=4?s=110" width="110px;" alt="Adam"/><br /><sub><b>Adam</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=adamboutcher" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://snksrv.com"><img src="https://avatars.githubusercontent.com/u/16104273?v=4?s=110" width="110px;" alt="Ian"/><br /><sub><b>Ian</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sneak-it" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://blog.bestlong.idv.tw/"><img src="https://avatars.githubusercontent.com/u/4023909?v=4?s=110" width="110px;" alt="Shao Yu-Lung (Allen)"/><br /><sub><b>Shao Yu-Lung (Allen)</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bestlong" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Haxatron"><img src="https://avatars.githubusercontent.com/u/76475453?v=4?s=110" width="110px;" alt="Haxatron"/><br /><sub><b>Haxatron</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Haxatron" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PlaneNuts"><img src="https://avatars.githubusercontent.com/u/88776392?v=4?s=110" width="110px;" alt="PlaneNuts"/><br /><sub><b>PlaneNuts</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PlaneNuts" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://bjcpgd.cias.rit.edu"><img src="https://avatars.githubusercontent.com/u/3842948?v=4?s=110" width="110px;" alt="Bradley Coudriet"/><br /><sub><b>Bradley Coudriet</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=exula" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://daltondur.st"><img src="https://avatars.githubusercontent.com/u/21966173?v=4?s=110" width="110px;" alt="Dalton Durst"/><br /><sub><b>Dalton Durst</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://adagiohealth.org"><img src="https://avatars.githubusercontent.com/u/38761237?v=4?s=110" width="110px;" alt="Alex Janes"/><br /><sub><b>Alex Janes</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=adagioajanes" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nuraeil"><img src="https://avatars.githubusercontent.com/u/32387849?v=4?s=110" width="110px;" alt="Nuraeil"/><br /><sub><b>Nuraeil</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nuraeil" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TenOfTens"><img src="https://avatars.githubusercontent.com/u/48162670?v=4?s=110" width="110px;" alt="TenOfTens"/><br /><sub><b>TenOfTens</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=TenOfTens" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://ditisjens.be/"><img src="https://avatars.githubusercontent.com/u/9415391?v=4?s=110" width="110px;" alt="waffle"/><br /><sub><b>waffle</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=insert-waffle" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qveensi"><img src="https://avatars.githubusercontent.com/u/19945501?v=4?s=110" width="110px;" alt="Yevhenii Huzii"/><br /><sub><b>Yevhenii Huzii</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=qveensi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/veenone"><img src="https://avatars.githubusercontent.com/u/3839381?v=4?s=110" width="110px;" alt="Achmad Fienan Rahardianto"/><br /><sub><b>Achmad Fienan Rahardianto</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=veenone" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chrisweirich"><img src="https://avatars.githubusercontent.com/u/97299851?v=4?s=110" width="110px;" alt="Christian Weirich"/><br /><sub><b>Christian Weirich</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chrisweirich" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/denzfarid"><img src="https://avatars.githubusercontent.com/u/1294403?v=4?s=110" width="110px;" alt="denzfarid"/><br /><sub><b>denzfarid</b></sub></a><br /></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ntbutler-nbcs"><img src="https://avatars.githubusercontent.com/u/94018771?v=4?s=110" width="110px;" alt="ntbutler-nbcs"/><br /><sub><b>ntbutler-nbcs</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://naveensrinivasan.dev"><img src="https://avatars.githubusercontent.com/u/172697?v=4?s=110" width="110px;" alt="Naveen"/><br /><sub><b>Naveen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=naveensrinivasan" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikeroq"><img src="https://avatars.githubusercontent.com/u/55674383?v=4?s=110" width="110px;" alt="Mike Roquemore"/><br /><sub><b>Mike Roquemore</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mikeroq" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/reederda"><img src="https://avatars.githubusercontent.com/u/7991086?v=4?s=110" width="110px;" alt="Daniel Reeder"/><br /><sub><b>Daniel Reeder</b></sub></a><br /><a href="#translation-reederda" title="Translation">🌍</a> <a href="#translation-reederda" title="Translation">🌍</a> <a href="https://github.com/snipe/snipe-it/commits?author=reederda" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vickyjaura183"><img src="https://avatars.githubusercontent.com/u/109422491?v=4?s=110" width="110px;" alt="vickyjaura183"/><br /><sub><b>vickyjaura183</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vickyjaura183" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/julian-piehl"><img src="https://avatars.githubusercontent.com/u/32363424?v=4?s=110" width="110px;" alt="Peace"/><br /><sub><b>Peace</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=julian-piehl" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kylegordon"><img src="https://avatars.githubusercontent.com/u/231528?v=4?s=110" width="110px;" alt="Kyle Gordon"/><br /><sub><b>Kyle Gordon</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=kylegordon" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.bfh.ch"><img src="https://avatars.githubusercontent.com/u/53009155?v=4?s=110" width="110px;" alt="Katharina Drexel"/><br /><sub><b>Katharina Drexel</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sunflowerbofh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://david.sferruzza.fr/"><img src="https://avatars.githubusercontent.com/u/1931963?v=4?s=110" width="110px;" alt="David Sferruzza"/><br /><sub><b>David Sferruzza</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dsferruzza" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rnelsonee"><img src="https://avatars.githubusercontent.com/u/19511639?v=4?s=110" width="110px;" alt="Rick Nelson"/><br /><sub><b>Rick Nelson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rnelsonee" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BasO12"><img src="https://avatars.githubusercontent.com/u/94169344?v=4?s=110" width="110px;" alt="BasO12"/><br /><sub><b>BasO12</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=BasO12" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Vautia"><img src="https://avatars.githubusercontent.com/u/111710123?v=4?s=110" width="110px;" alt="Vautia"/><br /><sub><b>Vautia</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Vautia" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.littlehart.net/atthekeyboard"><img src="https://avatars.githubusercontent.com/u/28321?v=4?s=110" width="110px;" alt="Chris Hartjes"/><br /><sub><b>Chris Hartjes</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chartjes" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geo-chen"><img src="https://avatars.githubusercontent.com/u/2404584?v=4?s=110" width="110px;" alt="geo-chen"/><br /><sub><b>geo-chen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=geo-chen" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nh314"><img src="https://avatars.githubusercontent.com/u/6006620?v=4?s=110" width="110px;" alt="Phan Nguyen"/><br /><sub><b>Phan Nguyen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nh314" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/StarlessNights"><img src="https://avatars.githubusercontent.com/u/115993812?v=4?s=110" width="110px;" alt="Iisakki Jaakkola"/><br /><sub><b>Iisakki Jaakkola</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=StarlessNights" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=110" width="110px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=eltociear" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lukasfehling"><img src="https://avatars.githubusercontent.com/u/56871540?v=4?s=110" width="110px;" alt="Lukas Fehling"/><br /><sub><b>Lukas Fehling</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=lukasfehling" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fernando-almeida"><img src="https://avatars.githubusercontent.com/u/1975990?v=4?s=110" width="110px;" alt="Fernando Almeida"/><br /><sub><b>Fernando Almeida</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fernando-almeida" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/akemidx"><img src="https://avatars.githubusercontent.com/u/116301219?v=4?s=110" width="110px;" alt="akemidx"/><br /><sub><b>akemidx</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=akemidx" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://oguz.site"><img src="https://avatars.githubusercontent.com/u/144778?v=4?s=110" width="110px;" alt="Oguz Bilgic"/><br /><sub><b>Oguz Bilgic</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=oguzbilgic" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/scoo73r"><img src="https://avatars.githubusercontent.com/u/9262438?v=4?s=110" width="110px;" alt="Scooter Crawford"/><br /><sub><b>Scooter Crawford</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=scoo73r" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/subdriven"><img src="https://avatars.githubusercontent.com/u/5957345?v=4?s=110" width="110px;" alt="subdriven"/><br /><sub><b>subdriven</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=subdriven" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AndrewSav"><img src="https://avatars.githubusercontent.com/u/658865?v=4?s=110" width="110px;" alt="Andrew Savinykh"/><br /><sub><b>Andrew Savinykh</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=AndrewSav" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://kenchan0130.github.io"><img src="https://avatars.githubusercontent.com/u/1155067?v=4?s=110" width="110px;" alt="Tadayuki Onishi"/><br /><sub><b>Tadayuki Onishi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=kenchan0130" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/floschoepfer"><img src="https://avatars.githubusercontent.com/u/112496896?v=4?s=110" width="110px;" alt="Florian"/><br /><sub><b>Florian</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=floschoepfer" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://spencerlong.com"><img src="https://avatars.githubusercontent.com/u/7305753?v=4?s=110" width="110px;" alt="Spencer Long"/><br /><sub><b>Spencer Long</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=spencerrlongg" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marcusmoore"><img src="https://avatars.githubusercontent.com/u/1141514?v=4?s=110" width="110px;" alt="Marcus Moore"/><br /><sub><b>Marcus Moore</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=marcusmoore" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Mezzle"><img src="https://avatars.githubusercontent.com/u/570639?v=4?s=110" width="110px;" alt="Martin Meredith"/><br /><sub><b>Martin Meredith</b></sub></a><br /></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://dboth.de"><img src="https://avatars.githubusercontent.com/u/5731963?v=4?s=110" width="110px;" alt="dboth"/><br /><sub><b>dboth</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dboth" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zacharyfleck"><img src="https://avatars.githubusercontent.com/u/87536651?v=4?s=110" width="110px;" alt="Zachary Fleck"/><br /><sub><b>Zachary Fleck</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=zacharyfleck" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vikaas-cyper"><img src="https://avatars.githubusercontent.com/u/74609912?v=4?s=110" width="110px;" alt="VIKAAS-A"/><br /><sub><b>VIKAAS-A</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vikaas-cyper" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ak-piracha"><img src="https://avatars.githubusercontent.com/u/88882041?v=4?s=110" width="110px;" alt="Abdul Kareem"/><br /><sub><b>Abdul Kareem</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ak-piracha" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NojoudAlshehri"><img src="https://avatars.githubusercontent.com/u/111287779?v=4?s=110" width="110px;" alt="NojoudAlshehri"/><br /><sub><b>NojoudAlshehri</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/stefanstidlffg"><img src="https://avatars.githubusercontent.com/u/54367449?v=4?s=110" width="110px;" alt="Stefan Stidl"/><br /><sub><b>Stefan Stidl</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=stefanstidlffg" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qay21"><img src="https://avatars.githubusercontent.com/u/87803479?v=4?s=110" width="110px;" alt="Quentin Aymard"/><br /><sub><b>Quentin Aymard</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=qay21" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cram42"><img src="https://avatars.githubusercontent.com/u/5396871?v=4?s=110" width="110px;" alt="Grant Le Roux"/><br /><sub><b>Grant Le Roux</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=cram42" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://@singrity"><img src="https://avatars.githubusercontent.com/u/58479551?v=4?s=110" width="110px;" alt="Bogdan"/><br /><sub><b>Bogdan</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Singrity" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mmanjos"><img src="https://avatars.githubusercontent.com/u/3483684?v=4?s=110" width="110px;" alt="mmanjos"/><br /><sub><b>mmanjos</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mmanjos" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://azooz2014.github.io/"><img src="https://avatars.githubusercontent.com/u/7429229?v=4?s=110" width="110px;" alt="Abdelaziz Faki"/><br /><sub><b>Abdelaziz Faki</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Azooz2014" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bilias"><img src="https://avatars.githubusercontent.com/u/47315739?v=4?s=110" width="110px;" alt="bilias"/><br /><sub><b>bilias</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bilias" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coach1988"><img src="https://avatars.githubusercontent.com/u/2565989?v=4?s=110" width="110px;" alt="coach1988"/><br /><sub><b>coach1988</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=coach1988" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mauro-miatello"><img src="https://avatars.githubusercontent.com/u/11910225?v=4?s=110" width="110px;" alt="MrM"/><br /><sub><b>MrM</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mauro-miatello" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/koiakoia"><img src="https://avatars.githubusercontent.com/u/60405354?v=4?s=110" width="110px;" alt="koiakoia"/><br /><sub><b>koiakoia</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=koiakoia" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mustafa-online"><img src="https://avatars.githubusercontent.com/u/5323832?v=4?s=110" width="110px;" alt="Mustafa Online"/><br /><sub><b>Mustafa Online</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mustafa-online" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/franceslui"><img src="https://avatars.githubusercontent.com/u/104601439?v=4?s=110" width="110px;" alt="franceslui"/><br /><sub><b>franceslui</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=franceslui" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Q4kK"><img src="https://avatars.githubusercontent.com/u/125313163?v=4?s=110" width="110px;" alt="Q4kK"/><br /><sub><b>Q4kK</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Q4kK" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/squintfox"><img src="https://avatars.githubusercontent.com/u/55590532?v=4?s=110" width="110px;" alt="squintfox"/><br /><sub><b>squintfox</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=squintfox" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jeffclay"><img src="https://avatars.githubusercontent.com/u/1380084?v=4?s=110" width="110px;" alt="Jeff Clay"/><br /><sub><b>Jeff Clay</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jeffclay" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PP-JN-RL"><img src="https://avatars.githubusercontent.com/u/52716446?v=4?s=110" width="110px;" alt="Phil J R"/><br /><sub><b>Phil J R</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=PP-JN-RL" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.corelight.com/"><img src="https://avatars.githubusercontent.com/u/1496725?v=4?s=110" width="110px;" alt="i_virus"/><br /><sub><b>i_virus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chandanchowdhury" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gitgrimbo"><img src="https://avatars.githubusercontent.com/u/1020541?v=4?s=110" width="110px;" alt="Paul Grime"/><br /><sub><b>Paul Grime</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gitgrimbo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://leeporte.co.uk"><img src="https://avatars.githubusercontent.com/u/922815?v=4?s=110" width="110px;" alt="Lee Porte"/><br /><sub><b>Lee Porte</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=LeePorte" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bryanlopezinc"><img src="https://avatars.githubusercontent.com/u/23613427?v=4?s=110" width="110px;" alt="BRYAN "/><br /><sub><b>BRYAN </b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bryanlopezinc" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=bryanlopezinc" title="Tests">⚠️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/U-H-T"><img src="https://avatars.githubusercontent.com/u/64061710?v=4?s=110" width="110px;" alt="U-H-T"/><br /><sub><b>U-H-T</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=U-H-T" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tyree"><img src="https://avatars.githubusercontent.com/u/5395363?v=4?s=110" width="110px;" alt="Matt Tyree"/><br /><sub><b>Matt Tyree</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Tyree" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://spoontux.net"><img src="https://avatars.githubusercontent.com/u/292081?v=4?s=110" width="110px;" alt="Florent Bervas"/><br /><sub><b>Florent Bervas</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=FlorentDotMe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://ditscheri.com"><img src="https://avatars.githubusercontent.com/u/4498077?v=4?s=110" width="110px;" alt="Daniel Albertsen"/><br /><sub><b>Daniel Albertsen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dbakan" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/r-xyz"><img src="https://avatars.githubusercontent.com/u/100710244?v=4?s=110" width="110px;" alt="r-xyz"/><br /><sub><b>r-xyz</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=r-xyz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DrekiDegga"><img src="https://avatars.githubusercontent.com/u/47491036?v=4?s=110" width="110px;" alt="Steven Mainor"/><br /><sub><b>Steven Mainor</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=DrekiDegga" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/arne-kroeger"><img src="https://avatars.githubusercontent.com/u/65785975?v=4?s=110" width="110px;" alt="arne-kroeger"/><br /><sub><b>arne-kroeger</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=arne-kroeger" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Glukose1"><img src="https://avatars.githubusercontent.com/u/167117705?v=4?s=110" width="110px;" alt="Glukose1"/><br /><sub><b>Glukose1</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Glukose1" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Scarzy"><img src="https://avatars.githubusercontent.com/u/1197791?v=4?s=110" width="110px;" alt="Scarzy"/><br /><sub><b>Scarzy</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Scarzy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/setpill"><img src="https://avatars.githubusercontent.com/u/37372069?v=4?s=110" width="110px;" alt="setpill"/><br /><sub><b>setpill</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=setpill" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/swift2512"><img src="https://avatars.githubusercontent.com/u/3755203?v=4?s=110" width="110px;" alt="swift2512"/><br /><sub><b>swift2512</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://darrenraineys.co.uk"><img src="https://avatars.githubusercontent.com/u/6136439?v=4?s=110" width="110px;" alt="Darren Rainey"/><br /><sub><b>Darren Rainey</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=DarrenRainey" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/maciej-poleszczyk"><img src="https://avatars.githubusercontent.com/u/133033121?v=4?s=110" width="110px;" alt="maciej-poleszczyk"/><br /><sub><b>maciej-poleszczyk</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sgross-emlix"><img src="https://avatars.githubusercontent.com/u/143394709?v=4?s=110" width="110px;" alt="Sebastian Groß"/><br /><sub><b>Sebastian Groß</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sgross-emlix" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AnouarTouati"><img src="https://avatars.githubusercontent.com/u/41107778?v=4?s=110" width="110px;" alt="Anouar Touati"/><br /><sub><b>Anouar Touati</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=AnouarTouati" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aHVzY2g"><img src="https://avatars.githubusercontent.com/u/25596663?v=4?s=110" width="110px;" alt="aHVzY2g"/><br /><sub><b>aHVzY2g</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=aHVzY2g" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://brlin.me"><img src="https://avatars.githubusercontent.com/u/13408130?v=4?s=110" width="110px;" alt="林博仁 Buo-ren Lin"/><br /><sub><b>林博仁 Buo-ren Lin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=brlin-tw" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://orbalia.pythonanywhere.com/"><img src="https://avatars.githubusercontent.com/u/18550946?v=4?s=110" width="110px;" alt="Adugna Gizaw"/><br /><sub><b>Adugna Gizaw</b></sub></a><br /><a href="#translation-addex12" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jostrander"><img src="https://avatars.githubusercontent.com/u/760989?v=4?s=110" width="110px;" alt="Jesse Ostrander"/><br /><sub><b>Jesse Ostrander</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jostrander" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/azmcnutt"><img src="https://avatars.githubusercontent.com/u/31522486?v=4?s=110" width="110px;" alt="James M"/><br /><sub><b>James M</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=azmcnutt" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Fiala06"><img src="https://avatars.githubusercontent.com/u/5183146?v=4?s=110" width="110px;" alt="Fiala06"/><br /><sub><b>Fiala06</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Fiala06" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ntaylor-86"><img src="https://avatars.githubusercontent.com/u/28693782?v=4?s=110" width="110px;" alt="Nathan Taylor"/><br /><sub><b>Nathan Taylor</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ntaylor-86" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fvollmer"><img src="https://avatars.githubusercontent.com/u/16699443?v=4?s=110" width="110px;" alt="fvollmer"/><br /><sub><b>fvollmer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fvollmer" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/36864"><img src="https://avatars.githubusercontent.com/u/109086466?v=4?s=110" width="110px;" alt="36864"/><br /><sub><b>36864</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=36864" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://clockwerx.blogspot.com/"><img src="https://avatars.githubusercontent.com/u/365751?v=4?s=110" width="110px;" alt="Daniel O'Connor"/><br /><sub><b>Daniel O'Connor</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=CloCkWeRX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BeatSpark"><img src="https://avatars.githubusercontent.com/u/102852568?v=4?s=110" width="110px;" alt="BeatSpark"/><br /><sub><b>BeatSpark</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=BeatSpark" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mrdahbi"><img src="https://avatars.githubusercontent.com/u/59203607?v=4?s=110" width="110px;" alt="mrdahbi"/><br /><sub><b>mrdahbi</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mrdahbi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://sr.solutions"><img src="https://avatars.githubusercontent.com/u/6661332?v=4?s=110" width="110px;" alt="Fabian Schmid"/><br /><sub><b>Fabian Schmid</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=chfsx" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.chrisolin.com"><img src="https://avatars.githubusercontent.com/u/1288116?v=4?s=110" width="110px;" alt="Chris Olin"/><br /><sub><b>Chris Olin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=realchrisolin" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mnemonicly"><img src="https://avatars.githubusercontent.com/u/3803132?v=4?s=110" width="110px;" alt="Dan"/><br /><sub><b>Dan</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mnemonicly" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NebelKreis"><img src="https://avatars.githubusercontent.com/u/43917728?v=4?s=110" width="110px;" alt="Nebel"/><br /><sub><b>Nebel</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=NebelKreis" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/test1337ahp"><img src="https://avatars.githubusercontent.com/u/132433803?v=4?s=110" width="110px;" alt="test1337ahp"/><br /><sub><b>test1337ahp</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=test1337ahp" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JonathonReinhart"><img src="https://avatars.githubusercontent.com/u/1916566?v=4?s=110" width="110px;" alt="Jonathon Reinhart"/><br /><sub><b>Jonathon Reinhart</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=JonathonReinhart" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aranar-pro"><img src="https://avatars.githubusercontent.com/u/484742?v=4?s=110" width="110px;" alt="aranar-pro"/><br /><sub><b>aranar-pro</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=aranar-pro" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/phil-flip"><img src="https://avatars.githubusercontent.com/u/27019397?v=4?s=110" width="110px;" alt="Phil"/><br /><sub><b>Phil</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=phil-flip" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://fe80.fr/"><img src="https://avatars.githubusercontent.com/u/6473460?v=4?s=110" width="110px;" alt="Steffy Fort"/><br /><sub><b>Steffy Fort</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fe80" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sorvani"><img src="https://avatars.githubusercontent.com/u/3302372?v=4?s=110" width="110px;" alt="Jared Busch"/><br /><sub><b>Jared Busch</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sorvani" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/seanborg-codethink"><img src="https://avatars.githubusercontent.com/u/111956991?v=4?s=110" width="110px;" alt="seanborg-codethink"/><br /><sub><b>seanborg-codethink</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=seanborg-codethink" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dkaatz"><img src="https://avatars.githubusercontent.com/u/160669961?v=4?s=110" width="110px;" alt="dkaatz"/><br /><sub><b>dkaatz</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dkaatz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://threema.id/74SF7MW6?text="><img src="https://avatars.githubusercontent.com/u/827205?v=4?s=110" width="110px;" alt="Daniel Ruf"/><br /><sub><b>Daniel Ruf</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=DanielRuf" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ahpaleus"><img src="https://avatars.githubusercontent.com/u/38883201?v=4?s=110" width="110px;" alt="ahpaleus"/><br /><sub><b>ahpaleus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ahpaleus" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mink-adao-duy"><img src="https://avatars.githubusercontent.com/u/22906055?v=4?s=110" width="110px;" alt="Anh DAO-DUY"/><br /><sub><b>Anh DAO-DUY</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mink-adao-duy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Serdnad"><img src="https://avatars.githubusercontent.com/u/4723453?v=4?s=110" width="110px;" alt="Andres Gutierrez"/><br /><sub><b>Andres Gutierrez</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Serdnad" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wewhite"><img src="https://avatars.githubusercontent.com/u/111083379?v=4?s=110" width="110px;" alt="Warren White"/><br /><sub><b>Warren White</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=wewhite" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://robintemme.de/"><img src="https://avatars.githubusercontent.com/u/2809241?v=4?s=110" width="110px;" alt="Robin Temme"/><br /><sub><b>Robin Temme</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=robintemme" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/herroworrd"><img src="https://avatars.githubusercontent.com/u/47008367?v=4?s=110" width="110px;" alt="herroworrd"/><br /><sub><b>herroworrd</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=herroworrd" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://mubiu.com/"><img src="https://avatars.githubusercontent.com/u/28558609?v=4?s=110" width="110px;" alt="vicleos"/><br /><sub><b>vicleos</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vicleos" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://thinkl33t.co.uk/"><img src="https://avatars.githubusercontent.com/u/1016780?v=4?s=110" width="110px;" alt="Bob Clough"/><br /><sub><b>Bob Clough</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=thinkl33t" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/brandon-bailey"><img src="https://avatars.githubusercontent.com/u/10648463?v=4?s=110" width="110px;" alt="Brandon Daniel Bailey"/><br /><sub><b>Brandon Daniel Bailey</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=brandon-bailey" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marcquark"><img src="https://avatars.githubusercontent.com/u/23556080?v=4?s=110" width="110px;" alt="Marc Bartelt"/><br /><sub><b>Marc Bartelt</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=marcquark" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/manu-crealytics"><img src="https://avatars.githubusercontent.com/u/18286893?v=4?s=110" width="110px;" alt="manu-crealytics"/><br /><sub><b>manu-crealytics</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=manu-crealytics" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.galaxy102.de/"><img src="https://avatars.githubusercontent.com/u/18245993?v=4?s=110" width="110px;" alt="Konstantin Köhring"/><br /><sub><b>Konstantin Köhring</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Galaxy102" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://deloz.net/"><img src="https://avatars.githubusercontent.com/u/685167?v=4?s=110" width="110px;" alt="Deloz"/><br /><sub><b>Deloz</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=deloz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mbrrg"><img src="https://avatars.githubusercontent.com/u/2682426?v=4?s=110" width="110px;" alt="Martin Berg"/><br /><sub><b>Martin Berg</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mbrrg" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nothing4You"><img src="https://avatars.githubusercontent.com/u/3694534?v=4?s=110" width="110px;" alt="Richard Schwab"/><br /><sub><b>Richard Schwab</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Nothing4You" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://rickheil.com/"><img src="https://avatars.githubusercontent.com/u/8959676?v=4?s=110" width="110px;" alt="Rick Heil"/><br /><sub><b>Rick Heil</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rickheil" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rosscdh"><img src="https://avatars.githubusercontent.com/u/397106?v=4?s=110" width="110px;" alt="Ross Crawford-d'Heureuse"/><br /><sub><b>Ross Crawford-d'Heureuse</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rosscdh" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/McG800"><img src="https://avatars.githubusercontent.com/u/1621107?v=4?s=110" width="110px;" alt="Ryan McGuire"/><br /><sub><b>Ryan McGuire</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=McG800" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SBrown2021"><img src="https://avatars.githubusercontent.com/u/77835667?v=4?s=110" width="110px;" alt="SBrown2021"/><br /><sub><b>SBrown2021</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=SBrown2021" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/serkanerip"><img src="https://avatars.githubusercontent.com/u/8780913?v=4?s=110" width="110px;" alt="Serkan"/><br /><sub><b>Serkan</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=serkanerip" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.yudelei.com/"><img src="https://avatars.githubusercontent.com/u/63188620?v=4?s=110" width="110px;" alt="Shanks"/><br /><sub><b>Shanks</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Shankschn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cendai-mis"><img src="https://avatars.githubusercontent.com/u/198525698?v=4?s=110" width="110px;" alt="cendai-mis"/><br /><sub><b>cendai-mis</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=cendai-mis" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://smcpeck.github.io/"><img src="https://avatars.githubusercontent.com/u/8724583?v=4?s=110" width="110px;" alt="Shaun McPeck"/><br /><sub><b>Shaun McPeck</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=smcpeck" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/snazy2000"><img src="https://avatars.githubusercontent.com/u/1378836?v=4?s=110" width="110px;" alt="Stephen"/><br /><sub><b>Stephen</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=snazy2000" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://nevets82.github.io/"><img src="https://avatars.githubusercontent.com/u/4462739?v=4?s=110" width="110px;" alt="Steven"/><br /><sub><b>Steven</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Nevets82" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://mateusvillar.com/"><img src="https://avatars.githubusercontent.com/u/29017267?v=4?s=110" width="110px;" alt="Mateus Villar"/><br /><sub><b>Mateus Villar</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Mateus-Romera" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mzack5020"><img src="https://avatars.githubusercontent.com/u/12749393?v=4?s=110" width="110px;" alt="Matthew Zackschewski"/><br /><sub><b>Matthew Zackschewski</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mzack5020" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.frei.media/"><img src="https://avatars.githubusercontent.com/u/12660103?v=4?s=110" width="110px;" alt="Matthias Frei"/><br /><sub><b>Matthias Frei</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=firefrei" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nticaric"><img src="https://avatars.githubusercontent.com/u/824840?v=4?s=110" width="110px;" alt="Nenad Ticaric"/><br /><sub><b>Nenad Ticaric</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nticaric" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Scorcher"><img src="https://avatars.githubusercontent.com/u/706439?v=4?s=110" width="110px;" alt="Nikolay Didenko"/><br /><sub><b>Nikolay Didenko</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Scorcher" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nunomaduro.com/sponsorships"><img src="https://avatars.githubusercontent.com/u/5457236?v=4?s=110" width="110px;" alt="Nuno Maduro"/><br /><sub><b>Nuno Maduro</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nunomaduro" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://tektikhq.com/"><img src="https://avatars.githubusercontent.com/u/8883074?v=4?s=110" width="110px;" alt="Oliver Walerys"/><br /><sub><b>Oliver Walerys</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=owalerys" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://keybase.io/rcmcdonald91"><img src="https://avatars.githubusercontent.com/u/3102039?v=4?s=110" width="110px;" alt="R. Christian McDonald"/><br /><sub><b>R. Christian McDonald</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rcmcdonald91" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nnix.net/"><img src="https://avatars.githubusercontent.com/u/1525581?v=4?s=110" width="110px;" alt="nix"/><br /><sub><b>nix</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=nixn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/octobunny"><img src="https://avatars.githubusercontent.com/u/55462380?v=4?s=110" width="110px;" alt="octobunny"/><br /><sub><b>octobunny</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=octobunny" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sreyemnayr"><img src="https://avatars.githubusercontent.com/u/8558670?v=4?s=110" width="110px;" alt="Ryan"/><br /><sub><b>Ryan</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sreyemnayr" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://benji.ltd/"><img src="https://avatars.githubusercontent.com/u/1501022?v=4?s=110" width="110px;" alt="p3nj"/><br /><sub><b>p3nj</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=p3nj" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/timwsuqld"><img src="https://avatars.githubusercontent.com/u/6201617?v=4?s=110" width="110px;" alt="Tim White"/><br /><sub><b>Tim White</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=timwsuqld" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yannikp"><img src="https://avatars.githubusercontent.com/u/22473767?v=4?s=110" width="110px;" alt="yannikp"/><br /><sub><b>yannikp</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=yannikp" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/viclou"><img src="https://avatars.githubusercontent.com/u/20525448?v=4?s=110" width="110px;" alt="victoria"/><br /><sub><b>victoria</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=viclou" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/valentyntu"><img src="https://avatars.githubusercontent.com/u/40685314?v=4?s=110" width="110px;" alt="Valentyn Tulub"/><br /><sub><b>Valentyn Tulub</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=valentyntu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://wouter0100.nl/"><img src="https://avatars.githubusercontent.com/u/864520?v=4?s=110" width="110px;" alt="Wouter van Os"/><br /><sub><b>Wouter van Os</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Wouter0100" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/wyatt-teeter"><img src="https://avatars.githubusercontent.com/u/3946540?v=4?s=110" width="110px;" alt="Wyatt Teeter"/><br /><sub><b>Wyatt Teeter</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=xWyatt" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/terwey"><img src="https://avatars.githubusercontent.com/u/1596124?v=4?s=110" width="110px;" alt="Yorick Terweijden"/><br /><sub><b>Yorick Terweijden</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=terwey" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bmkalle"><img src="https://avatars.githubusercontent.com/u/69298836?v=4?s=110" width="110px;" alt="bmkalle"/><br /><sub><b>bmkalle</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bmkalle" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bricelabelle"><img src="https://avatars.githubusercontent.com/u/28403467?v=4?s=110" width="110px;" alt="bricelabelle"/><br /><sub><b>bricelabelle</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bricelabelle" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/corydlamb"><img src="https://avatars.githubusercontent.com/u/97770090?v=4?s=110" width="110px;" alt="corydlamb"/><br /><sub><b>corydlamb</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=corydlamb" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/splash"><img src="https://avatars.githubusercontent.com/u/1154133?v=4?s=110" width="110px;" alt="Diogenes S. Jesus"/><br /><sub><b>Diogenes S. Jesus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=splashx" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dkmansion"><img src="https://avatars.githubusercontent.com/u/5826629?v=4?s=110" width="110px;" alt="D M"/><br /><sub><b>D M</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dkmansion" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jarli01"><img src="https://avatars.githubusercontent.com/u/14837699?v=4?s=110" width="110px;" alt="Dustin B"/><br /><sub><b>Dustin B</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Jarli01" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fabiang"><img src="https://avatars.githubusercontent.com/u/348344?v=4?s=110" width="110px;" alt="Fabian Grutschus"/><br /><sub><b>Fabian Grutschus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=fabiang" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MelonSmasher"><img src="https://avatars.githubusercontent.com/u/1491053?v=4?s=110" width="110px;" alt="MelonSmasher"/><br /><sub><b>MelonSmasher</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=MelonSmasher" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AlexanderWPapyrus"><img src="https://avatars.githubusercontent.com/u/80526133?v=4?s=110" width="110px;" alt="AlexanderWPapyrus"/><br /><sub><b>AlexanderWPapyrus</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=AlexanderWPapyrus" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/disc"><img src="https://avatars.githubusercontent.com/u/306231?v=4?s=110" width="110px;" alt="Alexandr Hacicheant"/><br /><sub><b>Alexandr Hacicheant</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=disc" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hex128.io/"><img src="https://avatars.githubusercontent.com/u/3032891?v=4?s=110" width="110px;" alt="Hex"/><br /><sub><b>Hex</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=hex128" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/arukompas"><img src="https://avatars.githubusercontent.com/u/8697942?v=4?s=110" width="110px;" alt="Arunas Skirius"/><br /><sub><b>Arunas Skirius</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=arukompas" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benperiton"><img src="https://avatars.githubusercontent.com/u/104396?v=4?s=110" width="110px;" alt="Ben Periton"/><br /><sub><b>Ben Periton</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=benperiton" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://wolfman.dev/"><img src="https://avatars.githubusercontent.com/u/11906832?v=4?s=110" width="110px;" alt="Byron Wolfman"/><br /><sub><b>Byron Wolfman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=byronwolfman" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CalvinSchwartz"><img src="https://avatars.githubusercontent.com/u/56485508?v=4?s=110" width="110px;" alt="Calvin"/><br /><sub><b>Calvin</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=CalvinSchwartz" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/juanfont"><img src="https://avatars.githubusercontent.com/u/181059?v=4?s=110" width="110px;" alt="Juan Font"/><br /><sub><b>Juan Font</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=juanfont" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/juhotaipale"><img src="https://avatars.githubusercontent.com/u/13137708?v=4?s=110" width="110px;" alt="Juho Taipale"/><br /><sub><b>Juho Taipale</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=juhotaipale" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KorvinSzanto"><img src="https://avatars.githubusercontent.com/u/1007419?v=4?s=110" width="110px;" alt="Korvin Szanto"/><br /><sub><b>Korvin Szanto</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=KorvinSzanto" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://lewisfoster.foo/"><img src="https://avatars.githubusercontent.com/u/8513053?v=4?s=110" width="110px;" alt="Lewis Foster"/><br /><sub><b>Lewis Foster</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=sniff122" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loganswartz"><img src="https://avatars.githubusercontent.com/u/33877541?v=4?s=110" width="110px;" alt="Logan Swartzendruber"/><br /><sub><b>Logan Swartzendruber</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=loganswartz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lopezio"><img src="https://avatars.githubusercontent.com/u/1156208?v=4?s=110" width="110px;" alt="Lorenzo P."/><br /><sub><b>Lorenzo P.</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=lopezio" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/m4us1ne"><img src="https://avatars.githubusercontent.com/u/33946590?v=4?s=110" width="110px;" alt="Lukas Jung"/><br /><sub><b>Lukas Jung</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=m4us1ne" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://leafedfox.xyz/"><img src="https://avatars.githubusercontent.com/u/10965027?v=4?s=110" width="110px;" alt="Ellie"/><br /><sub><b>Ellie</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=LeafedFox" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gastamper"><img src="https://avatars.githubusercontent.com/u/20960555?v=4?s=110" width="110px;" alt="GA Stamper"/><br /><sub><b>GA Stamper</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gastamper" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gl-pup"><img src="https://avatars.githubusercontent.com/u/206553556?v=4?s=110" width="110px;" alt="Guillaume Lefranc"/><br /><sub><b>Guillaume Lefranc</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=gl-pup" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dasjoe"><img src="https://avatars.githubusercontent.com/u/733892?v=4?s=110" width="110px;" alt="Hajo Möller"/><br /><sub><b>Hajo Möller</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dasjoe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pottom"><img src="https://avatars.githubusercontent.com/u/3420063?v=4?s=110" width="110px;" alt="Istvan Basa"/><br /><sub><b>Istvan Basa</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=pottom" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://jjasghar.github.io/"><img src="https://avatars.githubusercontent.com/u/810824?v=4?s=110" width="110px;" alt="JJ Asghar"/><br /><sub><b>JJ Asghar</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jjasghar" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JemCdo"><img src="https://avatars.githubusercontent.com/u/40404495?v=4?s=110" width="110px;" alt="James E. Msenga"/><br /><sub><b>James E. Msenga</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=JemCdo" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jfwiebe"><img src="https://avatars.githubusercontent.com/u/6865786?v=4?s=110" width="110px;" alt="Jan Felix Wiebe"/><br /><sub><b>Jan Felix Wiebe</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jfwiebe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nfon.com/"><img src="https://avatars.githubusercontent.com/u/43412008?v=4?s=110" width="110px;" alt="Jo Drexl"/><br /><sub><b>Jo Drexl</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=drexljo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/austinsasko"><img src="https://avatars.githubusercontent.com/u/4807843?v=4?s=110" width="110px;" alt="Austin Sasko"/><br /><sub><b>Austin Sasko</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=austinsasko" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://app.codacy.com/gh/snipe/snipe-it/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [](https://github.com/grokability/snipe-it/actions/workflows/tests.yml)
|
[](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://app.codacy.com/gh/grokability/snipe-it/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [](https://github.com/grokability/snipe-it/actions/workflows/tests.yml)
|
||||||
[](#contributing) [](https://discord.gg/yZFtShAcKk)
|
[](#contributing) [](https://discord.gg/yZFtShAcKk)
|
||||||
|
|
||||||
## Snipe-IT - Open Source Asset Management System
|
## Snipe-IT - Open Source Asset Management System
|
||||||
|
|||||||
32
app/Console/Commands/FixUpAssignedTypeWithoutAssignedTo.php
Normal file
32
app/Console/Commands/FixUpAssignedTypeWithoutAssignedTo.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class FixUpAssignedTypeWithoutAssignedTo extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'snipeit:assigned-type-fixup';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Fixes up assets that have an assigned_type but no assigned_to';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
DB::table('assets')->whereNotNull('assigned_type')->whereNull('assigned_to')->update(['assigned_type' => null]);
|
||||||
|
$this->info("Assets with an assigned_type but no assigned_to are fixed");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -182,7 +182,7 @@ class LdapSync extends Command
|
|||||||
// Inject location information fields
|
// Inject location information fields
|
||||||
for ($i = 0; $i < $results['count']; $i++) {
|
for ($i = 0; $i < $results['count']; $i++) {
|
||||||
$results[$i]['ldap_location_override'] = false;
|
$results[$i]['ldap_location_override'] = false;
|
||||||
$results[$i]['location_id'] = 0;
|
$results[$i]['location_id'] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab subsets based on location-specific DNs, and overwrite location for these users.
|
// Grab subsets based on location-specific DNs, and overwrite location for these users.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
@@ -66,8 +66,8 @@ class PaveIt extends Command
|
|||||||
foreach ($custom_fields as $custom_field) {
|
foreach ($custom_fields as $custom_field) {
|
||||||
$this->info('DROP the '.$custom_field->db_column.' column from assets as well.');
|
$this->info('DROP the '.$custom_field->db_column.' column from assets as well.');
|
||||||
|
|
||||||
if (\Schema::hasColumn('assets', $custom_field->db_column)) {
|
if (Schema::hasColumn('assets', $custom_field->db_column)) {
|
||||||
\Schema::table('assets', function ($table) use ($custom_field) {
|
Schema::table('assets', function ($table) use ($custom_field) {
|
||||||
$table->dropColumn($custom_field->db_column);
|
$table->dropColumn($custom_field->db_column);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -84,8 +84,8 @@ class PaveIt extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Leave in the demo oauth keys so we don't have to reset them every day in the demos
|
// Leave in the demo oauth keys so we don't have to reset them every day in the demos
|
||||||
\DB::statement('delete from oauth_clients WHERE id > 2');
|
DB::statement('delete from oauth_clients WHERE id > 2');
|
||||||
\DB::statement('delete from oauth_access_tokens WHERE id > 2');
|
DB::statement('delete from oauth_access_tokens WHERE user_id > 2');
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,9 +329,9 @@ class RestoreFromBackup extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$good_extensions = ['png', 'gif', 'jpg', 'svg', 'jpeg', 'doc', 'docx', 'pdf', 'txt',
|
|
||||||
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico', 'avif'
|
$good_extensions = config('filesystems.allowed_upload_extensions_array');
|
||||||
];
|
|
||||||
foreach (array_merge($private_files, $public_files) as $file) {
|
foreach (array_merge($private_files, $public_files) as $file) {
|
||||||
$has_wildcard = (strpos($file, '*') !== false);
|
$has_wildcard = (strpos($file, '*') !== false);
|
||||||
if ($has_wildcard) {
|
if ($has_wildcard) {
|
||||||
|
|||||||
@@ -99,8 +99,11 @@ class SendAcceptanceReminder extends Command
|
|||||||
foreach ($no_email_list as $user) {
|
foreach ($no_email_list as $user) {
|
||||||
$rows[] = [$user['id'], $user['name']];
|
$rows[] = [$user['id'], $user['name']];
|
||||||
}
|
}
|
||||||
$this->info("The following users do not have an email address:");
|
|
||||||
$this->table($headers, $rows);
|
if (!empty($rows)) {
|
||||||
|
$this->info("The following users do not have an email address:");
|
||||||
|
$this->table($headers, $rows);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class CheckoutableCheckedIn
|
|||||||
$this->checkedOutTo = $checkedOutTo;
|
$this->checkedOutTo = $checkedOutTo;
|
||||||
$this->checkedInBy = $checkedInBy;
|
$this->checkedInBy = $checkedInBy;
|
||||||
$this->note = $note;
|
$this->note = $note;
|
||||||
$this->action_date = $action_date ?? date('Y-m-d');
|
$this->action_date = $action_date ?? date('Y-m-d H:i:s');
|
||||||
$this->originalValues = $originalValues;
|
$this->originalValues = $originalValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
use Throwable;
|
use Throwable;
|
||||||
use JsonException;
|
use JsonException;
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
|
use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
@@ -107,18 +108,25 @@ class Handler extends ExceptionHandler
|
|||||||
|
|
||||||
$statusCode = $e->getStatusCode();
|
$statusCode = $e->getStatusCode();
|
||||||
|
|
||||||
|
// API throttle requests are handled in the RouteServiceProvider configureRateLimiting() method, so we don't need to handle them here
|
||||||
switch ($e->getStatusCode()) {
|
switch ($e->getStatusCode()) {
|
||||||
case '404':
|
case '404':
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
|
||||||
case '429':
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Too many requests'), 429);
|
|
||||||
case '405':
|
case '405':
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
|
||||||
default:
|
default:
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This handles API validation exceptions that happen at the Form Request level, so they
|
||||||
|
// never even get to the controller where we normally nicely format JSON responses
|
||||||
|
if ($e instanceof ValidationException) {
|
||||||
|
$response = $this->invalidJson($request, $e);
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $e->errors()), 200);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -143,6 +151,10 @@ class Handler extends ExceptionHandler
|
|||||||
$route = 'maintenances.index';
|
$route = 'maintenances.index';
|
||||||
} elseif ($route === 'licenseseats.index') {
|
} elseif ($route === 'licenseseats.index') {
|
||||||
$route = 'licenses.index';
|
$route = 'licenses.index';
|
||||||
|
} elseif ($route === 'customfields.index') {
|
||||||
|
$route = 'fields.index';
|
||||||
|
} elseif ($route === 'customfieldsets.index') {
|
||||||
|
$route = 'fields.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
@@ -201,6 +213,7 @@ class Handler extends ExceptionHandler
|
|||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->reportable(function (Throwable $e) {
|
$this->reportable(function (Throwable $e) {
|
||||||
//
|
//
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use App\Models\Setting;
|
|||||||
use App\Models\Statuslabel;
|
use App\Models\Statuslabel;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@@ -722,8 +723,8 @@ class Helper
|
|||||||
// The check and message that the user is still using the deprecated version
|
// The check and message that the user is still using the deprecated version
|
||||||
$deprecations = [
|
$deprecations = [
|
||||||
'ms_teams_deprecated' => array(
|
'ms_teams_deprecated' => array(
|
||||||
'check' => !Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows'),
|
'check' => !Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows') && (Setting::getSettings()->webhook_selected === 'microsoft'),
|
||||||
'message' => 'The Microsoft Teams webhook URL being used will be deprecated Jan 31st, 2025. <a class="btn btn-primary" href="' . route('settings.slack.index') . '">Change webhook endpoint</a>'),
|
'message' => 'The Microsoft Teams webhook URL being used will be deprecated Dec 31st, 2025. <a class="btn btn-primary" href="' . route('settings.slack.index') . '">Change webhook endpoint</a>'),
|
||||||
];
|
];
|
||||||
|
|
||||||
// if item of concern is being used and its being used with the deprecated values return the notification array.
|
// if item of concern is being used and its being used with the deprecated values return the notification array.
|
||||||
@@ -876,6 +877,48 @@ class Helper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the file is a video, so we can show a preview
|
||||||
|
*
|
||||||
|
* @param File $file
|
||||||
|
* @return string | Boolean
|
||||||
|
* @author [B. Wetherington] [<bwetherington@grokability.com>]
|
||||||
|
* @since [v8.1.18]
|
||||||
|
*/
|
||||||
|
public static function checkUploadIsVideo($file)
|
||||||
|
{
|
||||||
|
$finfo = @finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
|
||||||
|
$filetype = @finfo_file($finfo, $file);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
if (($filetype == 'video/mp4') || ($filetype == 'video/quicktime') || ($filetype == 'video/mpeg') || ($filetype == 'video/ogg') || ($filetype == 'video/webm') || ($filetype == 'video/x-msvide')) {
|
||||||
|
return $filetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the file is audio, so we can show a preview
|
||||||
|
*
|
||||||
|
* @param File $file
|
||||||
|
* @return string | Boolean
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v3.0]
|
||||||
|
*/
|
||||||
|
public static function checkUploadIsAudio($file)
|
||||||
|
{
|
||||||
|
$finfo = @finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
|
||||||
|
$filetype = @finfo_file($finfo, $file);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
if (($filetype == 'audio/mpeg') || ($filetype == 'audio/ogg')) {
|
||||||
|
return $filetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks through the permissions in the permissions config file and determines if
|
* Walks through the permissions in the permissions config file and determines if
|
||||||
* permissions are granted based on a $selected_arr array.
|
* permissions are granted based on a $selected_arr array.
|
||||||
@@ -1170,6 +1213,15 @@ class Helper
|
|||||||
// Misc
|
// Misc
|
||||||
'pdf' => 'far fa-file-pdf',
|
'pdf' => 'far fa-file-pdf',
|
||||||
'lic' => 'far fa-save',
|
'lic' => 'far fa-save',
|
||||||
|
|
||||||
|
// video
|
||||||
|
'mov' => 'fa-solid fa-video',
|
||||||
|
'mp4' => 'fa-solid fa-video',
|
||||||
|
|
||||||
|
// audio
|
||||||
|
'ogg' => 'fa-solid fa-file-audio',
|
||||||
|
'mp3' => 'fa-solid fa-file-audio',
|
||||||
|
'wav' => 'fa-solid fa-file-audio',
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($extension && array_key_exists($extension, $allowedExtensionMap)) {
|
if ($extension && array_key_exists($extension, $allowedExtensionMap)) {
|
||||||
@@ -1313,25 +1365,24 @@ class Helper
|
|||||||
switch ($item) {
|
switch ($item) {
|
||||||
case 'asset':
|
case 'asset':
|
||||||
return 'fas fa-barcode';
|
return 'fas fa-barcode';
|
||||||
break;
|
|
||||||
case 'accessory':
|
case 'accessory':
|
||||||
return 'fas fa-keyboard';
|
return 'fas fa-keyboard';
|
||||||
break;
|
|
||||||
case 'component':
|
case 'component':
|
||||||
return 'fas fa-hdd';
|
return 'fas fa-hdd';
|
||||||
break;
|
|
||||||
case 'consumable':
|
case 'consumable':
|
||||||
return 'fas fa-tint';
|
return 'fas fa-tint';
|
||||||
break;
|
|
||||||
case 'license':
|
case 'license':
|
||||||
return 'far fa-save';
|
return 'far fa-save';
|
||||||
break;
|
|
||||||
case 'location':
|
case 'location':
|
||||||
return 'fas fa-map-marker-alt';
|
return 'fas fa-map-marker-alt';
|
||||||
break;
|
|
||||||
case 'user':
|
case 'user':
|
||||||
return 'fas fa-user';
|
return 'fas fa-user';
|
||||||
break;
|
case 'supplier':
|
||||||
|
return 'fa-solid fa-store';
|
||||||
|
case 'manufacturer':
|
||||||
|
return 'fa-solid fa-building';
|
||||||
|
case 'category':
|
||||||
|
return 'fa-solid fa-table-columns';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1481,68 +1532,64 @@ class Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static public function getRedirectOption($request, $id, $table, $item_id = null)
|
static public function getRedirectOption($request, $id, $table, $item_id = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
$redirect_option = Session::get('redirect_option');
|
$redirect_option = Session::get('redirect_option') ?? $request->redirect_option;
|
||||||
$checkout_to_type = Session::get('checkout_to_type');
|
$checkout_to_type = Session::get('checkout_to_type') ?? null;
|
||||||
$checkedInFrom = Session::get('checkedInFrom');
|
$checkedInFrom = Session::get('checkedInFrom');
|
||||||
$other_redirect = Session::get('other_redirect');
|
$other_redirect = Session::get('other_redirect');
|
||||||
|
$backUrl = Session::pull('back_url', route('home'));
|
||||||
|
|
||||||
|
// return to previous page
|
||||||
|
if ($redirect_option === 'back') {
|
||||||
|
if ($backUrl === route('home')) {
|
||||||
|
return redirect()->to($backUrl)
|
||||||
|
->with('warning', trans('general.page_error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to($backUrl);
|
||||||
|
}
|
||||||
|
|
||||||
// return to index
|
// return to index
|
||||||
if ($redirect_option == 'index') {
|
if ($redirect_option == 'index') {
|
||||||
switch ($table) {
|
return match ($table) {
|
||||||
case "Assets":
|
'Assets' => redirect()->route('hardware.index'),
|
||||||
return route('hardware.index');
|
'Users' => redirect()->route('users.index'),
|
||||||
case "Users":
|
'Licenses' => redirect()->route('licenses.index'),
|
||||||
return route('users.index');
|
'Accessories' => redirect()->route('accessories.index'),
|
||||||
case "Licenses":
|
'Components' => redirect()->route('components.index'),
|
||||||
return route('licenses.index');
|
'Consumables' => redirect()->route('consumables.index'),
|
||||||
case "Accessories":
|
};
|
||||||
return route('accessories.index');
|
|
||||||
case "Components":
|
|
||||||
return route('components.index');
|
|
||||||
case "Consumables":
|
|
||||||
return route('consumables.index');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return to thing being assigned
|
// return to thing being assigned
|
||||||
if ($redirect_option == 'item') {
|
if ($redirect_option == 'item') {
|
||||||
switch ($table) {
|
return match ($table) {
|
||||||
case "Assets":
|
'Assets' => redirect()->route('hardware.show', $id ?? $item_id),
|
||||||
return route('hardware.show', $id ?? $item_id);
|
'Users' => redirect()->route('users.show', $id ?? $item_id),
|
||||||
case "Users":
|
'Licenses' => redirect()->route('licenses.show', $id ?? $item_id),
|
||||||
return route('users.show', $id ?? $item_id);
|
'Accessories' => redirect()->route('accessories.show', $id ?? $item_id),
|
||||||
case "Licenses":
|
'Components' => redirect()->route('components.show', $id ?? $item_id),
|
||||||
return route('licenses.show', $id ?? $item_id);
|
'Consumables' => redirect()->route('consumables.show', $id ?? $item_id),
|
||||||
case "Accessories":
|
};
|
||||||
return route('accessories.show', $id ?? $item_id);
|
|
||||||
case "Components":
|
|
||||||
return route('components.show', $id ?? $item_id);
|
|
||||||
case "Consumables":
|
|
||||||
return route('consumables.show', $id ?? $item_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return to assignment target
|
// return to assignment target
|
||||||
if ($redirect_option == 'target') {
|
if ($redirect_option == 'target') {
|
||||||
switch ($checkout_to_type) {
|
return match ($checkout_to_type) {
|
||||||
case 'user':
|
'user' => redirect()->route('users.show', $request->assigned_user ?? $checkedInFrom),
|
||||||
return route('users.show', $request->assigned_user ?? $checkedInFrom);
|
'location' => redirect()->route('locations.show', $request->assigned_location ?? $checkedInFrom),
|
||||||
case 'location':
|
'asset' => redirect()->route('hardware.show', $request->assigned_asset ?? $checkedInFrom),
|
||||||
return route('locations.show', $request->assigned_location ?? $checkedInFrom);
|
};
|
||||||
case 'asset':
|
|
||||||
return route('hardware.show', $request->assigned_asset ?? $checkedInFrom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return to somewhere else
|
// return to somewhere else
|
||||||
if ($redirect_option == 'other_redirect') {
|
if ($redirect_option == 'other_redirect') {
|
||||||
switch ($other_redirect) {
|
return match ($other_redirect) {
|
||||||
case 'audit':
|
'audit' => redirect()->route('assets.audit.due'),
|
||||||
return route('assets.audit.due');
|
'model' => redirect()->route('models.show', $request->model_id),
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ class StorageHelper
|
|||||||
$disk = config('filesystems.default');
|
$disk = config('filesystems.default');
|
||||||
}
|
}
|
||||||
switch (config("filesystems.disks.$disk.driver")) {
|
switch (config("filesystems.disks.$disk.driver")) {
|
||||||
case 'local':
|
case 'local':
|
||||||
return response()->download(Storage::disk($disk)->path($filename)); //works for PRIVATE or public?!
|
return response()->download(Storage::disk($disk)->path($filename)); //works for PRIVATE or public?!
|
||||||
|
|
||||||
case 's3':
|
case 's3':
|
||||||
return redirect()->away(Storage::disk($disk)->temporaryUrl($filename, now()->addMinutes(5))); //works for private or public, I guess?
|
return redirect()->away(Storage::disk($disk)->temporaryUrl($filename, now()->addMinutes(5))); //works for private or public, I guess?
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Storage::disk($disk)->download($filename);
|
return Storage::disk($disk)->download($filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,21 +33,29 @@ class StorageHelper
|
|||||||
* to determine that they are safe to display inline.
|
* to determine that they are safe to display inline.
|
||||||
*
|
*
|
||||||
* @author <A. Gianotto> [<snipe@snipe.net]>
|
* @author <A. Gianotto> [<snipe@snipe.net]>
|
||||||
* @since v7.0.14
|
* @since v7.0.14
|
||||||
* @param $file_with_path
|
* @param $file_with_path
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function allowSafeInline($file_with_path) {
|
public static function allowSafeInline($file_with_path)
|
||||||
|
{
|
||||||
|
|
||||||
$allowed_inline = [
|
$allowed_inline = [
|
||||||
'pdf',
|
|
||||||
'svg',
|
|
||||||
'jpg',
|
|
||||||
'gif',
|
|
||||||
'svg',
|
|
||||||
'avif',
|
'avif',
|
||||||
'webp',
|
'gif',
|
||||||
|
'gif',
|
||||||
|
'jpg',
|
||||||
|
'mov',
|
||||||
|
'mp3',
|
||||||
|
'mp4',
|
||||||
|
'ogg',
|
||||||
|
'pdf',
|
||||||
'png',
|
'png',
|
||||||
|
'svg',
|
||||||
|
'svg',
|
||||||
|
'wav',
|
||||||
|
'webm',
|
||||||
|
'webp',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -59,10 +67,24 @@ class StorageHelper
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFiletype($file_with_path)
|
||||||
|
{
|
||||||
|
|
||||||
|
// The file exists and is allowed to be displayed inline
|
||||||
|
if (Storage::exists($file_with_path)) {
|
||||||
|
return pathinfo($file_with_path, PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decide whether to show the file inline or download it.
|
* Decide whether to show the file inline or download it.
|
||||||
*/
|
*/
|
||||||
public static function showOrDownloadFile($file, $filename) {
|
public static function showOrDownloadFile($file, $filename)
|
||||||
|
{
|
||||||
|
|
||||||
$headers = [];
|
$headers = [];
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ class AccessoriesController extends Controller
|
|||||||
// Was the accessory created?
|
// Was the accessory created?
|
||||||
if ($accessory->save()) {
|
if ($accessory->save()) {
|
||||||
// Redirect to the new accessory page
|
// Redirect to the new accessory page
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.create.success'));
|
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
|
||||||
|
->with('success', trans('admin/accessories/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
|
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
|
||||||
@@ -167,7 +168,8 @@ class AccessoriesController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($accessory->save()) {
|
if ($accessory->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.update.success'));
|
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
|
||||||
|
->with('success', trans('admin/accessories/message.update.success'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||||
@@ -220,7 +222,10 @@ class AccessoriesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Accessory $accessory) : View | RedirectResponse
|
public function show(Accessory $accessory) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id);
|
$accessory->loadCount('checkouts as checkouts_count');
|
||||||
|
|
||||||
|
$accessory->load(['adminuser' => fn($query) => $query->withTrashed()]);
|
||||||
|
|
||||||
$this->authorize('view', $accessory);
|
$this->authorize('view', $accessory);
|
||||||
return view('accessories.view', compact('accessory'));
|
return view('accessories.view', compact('accessory'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ class AccessoryCheckinController extends Controller
|
|||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.checkin.success'));
|
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
|
||||||
|
->with('success', trans('admin/accessories/message.checkin.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the accessory management page with error
|
// Redirect to the accessory management page with error
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class AccessoryCheckoutController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
// Redirect to the new accessory page
|
// Redirect to the new accessory page
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))
|
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
|
||||||
->with('success', trans('admin/accessories/message.checkout.success'));
|
->with('success', trans('admin/accessories/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Events\CheckoutDeclined;
|
|||||||
use App\Events\ItemAccepted;
|
use App\Events\ItemAccepted;
|
||||||
use App\Events\ItemDeclined;
|
use App\Events\ItemDeclined;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Mail\CheckoutAcceptanceResponseMail;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
@@ -20,9 +21,12 @@ use App\Models\License;
|
|||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use App\Notifications\AcceptanceAssetAcceptedNotification;
|
use App\Notifications\AcceptanceAssetAcceptedNotification;
|
||||||
|
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
|
||||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Http\Controllers\SettingsController;
|
use App\Http\Controllers\SettingsController;
|
||||||
@@ -148,6 +152,8 @@ class AcceptanceController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$assigned_user = User::find($acceptance->assigned_to_id);
|
||||||
// this is horrible
|
// this is horrible
|
||||||
switch($acceptance->checkoutable_type){
|
switch($acceptance->checkoutable_type){
|
||||||
case 'App\Models\Asset':
|
case 'App\Models\Asset':
|
||||||
@@ -157,35 +163,30 @@ class AcceptanceController extends Controller
|
|||||||
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
$display_model = $asset_model->name;
|
$display_model = $asset_model->name;
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'App\Models\Accessory':
|
case 'App\Models\Accessory':
|
||||||
$pdf_view_route ='account.accept.accept-accessory-eula';
|
$pdf_view_route ='account.accept.accept-accessory-eula';
|
||||||
$accessory = Accessory::find($item->id);
|
$accessory = Accessory::find($item->id);
|
||||||
$display_model = $accessory->name;
|
$display_model = $accessory->name;
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'App\Models\LicenseSeat':
|
case 'App\Models\LicenseSeat':
|
||||||
$pdf_view_route ='account.accept.accept-license-eula';
|
$pdf_view_route ='account.accept.accept-license-eula';
|
||||||
$license = License::find($item->license_id);
|
$license = License::find($item->license_id);
|
||||||
$display_model = $license->name;
|
$display_model = $license->name;
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'App\Models\Component':
|
case 'App\Models\Component':
|
||||||
$pdf_view_route ='account.accept.accept-component-eula';
|
$pdf_view_route ='account.accept.accept-component-eula';
|
||||||
$component = Component::find($item->id);
|
$component = Component::find($item->id);
|
||||||
$display_model = $component->name;
|
$display_model = $component->name;
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'App\Models\Consumable':
|
case 'App\Models\Consumable':
|
||||||
$pdf_view_route ='account.accept.accept-consumable-eula';
|
$pdf_view_route ='account.accept.accept-consumable-eula';
|
||||||
$consumable = Consumable::find($item->id);
|
$consumable = Consumable::find($item->id);
|
||||||
$display_model = $consumable->name;
|
$display_model = $consumable->name;
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
|
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
|
||||||
@@ -226,7 +227,7 @@ class AcceptanceController extends Controller
|
|||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
||||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
||||||
'assigned_to' => $assigned_to,
|
'assigned_to' => $assigned_user->present()->fullName,
|
||||||
'company_name' => $branding_settings->site_name,
|
'company_name' => $branding_settings->site_name,
|
||||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||||
'logo' => $path_logo,
|
'logo' => $path_logo,
|
||||||
@@ -240,6 +241,19 @@ class AcceptanceController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||||
|
|
||||||
|
// Send the PDF to the signing user
|
||||||
|
if (($request->input('send_copy') == '1') && ($assigned_user->email !='')) {
|
||||||
|
|
||||||
|
// Add the attachment for the signing user into the $data array
|
||||||
|
$data['file'] = $pdf_filename;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$assigned_user->notify(new AcceptanceAssetAcceptedToUserNotification($data));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::warning($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -337,6 +351,21 @@ class AcceptanceController extends Controller
|
|||||||
$return_msg = trans('admin/users/message.declined');
|
$return_msg = trans('admin/users/message.declined');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($acceptance->alert_on_response_id) {
|
||||||
|
try {
|
||||||
|
$recipient = User::find($acceptance->alert_on_response_id);
|
||||||
|
|
||||||
|
if ($recipient) {
|
||||||
|
Mail::to($recipient)->send(new CheckoutAcceptanceResponseMail(
|
||||||
|
$acceptance,
|
||||||
|
$recipient,
|
||||||
|
$request->input('asset_acceptance') === 'accepted',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::warning($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||||
|
|
||||||
|
|||||||
@@ -1,200 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
|
||||||
use App\Http\Transformers\UploadedFilesTransformer;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use App\Helpers\Helper;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Asset;
|
|
||||||
use App\Models\Actionlog;
|
|
||||||
use App\Http\Requests\UploadFileRequest;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class controls file related actions related
|
|
||||||
* to assets for the Snipe-IT Asset Management application.
|
|
||||||
*
|
|
||||||
* Based on the Assets/AssetFilesController by A. Gianotto <snipe@snipe.net>
|
|
||||||
*
|
|
||||||
* @version v1.0
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
class AssetFilesController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Accepts a POST to upload a file to the server.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\UploadFileRequest $request
|
|
||||||
* @param int $assetId
|
|
||||||
* @since [v6.0]
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
public function store(UploadFileRequest $request, $assetId = null) : JsonResponse
|
|
||||||
{
|
|
||||||
// Start by checking if the asset being acted upon exists
|
|
||||||
if (! $asset = Asset::find($assetId)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we are allowed to update this asset
|
|
||||||
$this->authorize('update', $asset);
|
|
||||||
|
|
||||||
if ($request->hasFile('file')) {
|
|
||||||
// If the file storage directory doesn't exist; create it
|
|
||||||
if (! Storage::exists('private_uploads/assets')) {
|
|
||||||
Storage::makeDirectory('private_uploads/assets', 775);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop over the attached files and add them to the asset
|
|
||||||
foreach ($request->file('file') as $file) {
|
|
||||||
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
|
||||||
|
|
||||||
$asset->logUpload($file_name, e($request->get('notes')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done - report success
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.upload.success')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only reach here if no files were included in the POST, so tell the user this
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.upload.nofiles')), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List the files for an asset.
|
|
||||||
*
|
|
||||||
* @param int $assetId
|
|
||||||
* @since [v6.0]
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
public function list(Asset $asset, Request $request) : JsonResponse | array
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->authorize('view', $asset);
|
|
||||||
|
|
||||||
$allowed_columns =
|
|
||||||
[
|
|
||||||
'id',
|
|
||||||
'filename',
|
|
||||||
'eol',
|
|
||||||
'notes',
|
|
||||||
'created_at',
|
|
||||||
'updated_at',
|
|
||||||
];
|
|
||||||
|
|
||||||
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')->where('item_type', '=', Asset::class)->where('item_id', '=', $asset->id);
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
|
||||||
$files = $files->TextSearch($request->input('search'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
|
||||||
$offset = ($request->input('offset') > $files->count()) ? $files->count() : abs($request->input('offset'));
|
|
||||||
$limit = app('api_limit_value');
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
|
||||||
$files = $files->orderBy($sort, $order);
|
|
||||||
|
|
||||||
$files = $files->skip($offset)->take($limit)->get();
|
|
||||||
return (new UploadedFilesTransformer())->transformFiles($files, $files->count());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for permissions and display the file.
|
|
||||||
*
|
|
||||||
* @param int $assetId
|
|
||||||
* @param int $fileId
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v6.0]
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
public function show(Asset $asset, $fileId = null) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
|
||||||
{
|
|
||||||
|
|
||||||
// the asset is valid
|
|
||||||
if (isset($asset->id)) {
|
|
||||||
$this->authorize('view', $asset);
|
|
||||||
|
|
||||||
// Check that the file being requested exists for the asset
|
|
||||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.no_match', ['id' => $fileId])), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Form the full filename with path
|
|
||||||
$file = 'private_uploads/assets/'.$log->filename;
|
|
||||||
Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
if ($log->action_type == 'audit') {
|
|
||||||
$file = 'private_uploads/audits/'.$log->filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the file actually exists on the filesystem
|
|
||||||
if (! Storage::exists($file)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.does_not_exist', ['id' => $fileId])), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request('inline') == 'true') {
|
|
||||||
|
|
||||||
$headers = [
|
|
||||||
'Content-Disposition' => 'inline',
|
|
||||||
];
|
|
||||||
|
|
||||||
return Storage::download($file, $log->filename, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return StorageHelper::downloader($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send back an error message
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error', ['id' => $fileId])), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the associated file
|
|
||||||
*
|
|
||||||
* @param int $assetId
|
|
||||||
* @param int $fileId
|
|
||||||
* @since [v6.0]
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
public function destroy(Asset $asset, $fileId = null) : JsonResponse
|
|
||||||
{
|
|
||||||
|
|
||||||
$rel_path = 'private_uploads/assets';
|
|
||||||
|
|
||||||
// the asset is valid
|
|
||||||
if (isset($asset->id)) {
|
|
||||||
$this->authorize('update', $asset);
|
|
||||||
|
|
||||||
// Check for the file
|
|
||||||
$log = Actionlog::find($fileId);
|
|
||||||
|
|
||||||
if ($log) {
|
|
||||||
// Check the file actually exists, and delete it
|
|
||||||
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
|
||||||
Storage::delete($rel_path.'/'.$log->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the record of the file
|
|
||||||
$log->delete();
|
|
||||||
|
|
||||||
// All deleting done - notify the user of success
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.deletefile.success')), 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The file doesn't seem to really exist, so report an error
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -75,6 +75,7 @@ class AssetMaintenancesController extends Controller
|
|||||||
'serial',
|
'serial',
|
||||||
'created_by',
|
'created_by',
|
||||||
'supplier',
|
'supplier',
|
||||||
|
'location',
|
||||||
'is_warranty',
|
'is_warranty',
|
||||||
'status_label',
|
'status_label',
|
||||||
];
|
];
|
||||||
@@ -98,6 +99,9 @@ class AssetMaintenancesController extends Controller
|
|||||||
case 'serial':
|
case 'serial':
|
||||||
$maintenances = $maintenances->OrderByAssetSerial($order);
|
$maintenances = $maintenances->OrderByAssetSerial($order);
|
||||||
break;
|
break;
|
||||||
|
case 'location':
|
||||||
|
$maintenances = $maintenances->OrderLocationName($order);
|
||||||
|
break;
|
||||||
case 'status_label':
|
case 'status_label':
|
||||||
$maintenances = $maintenances->OrderStatusName($order);
|
$maintenances = $maintenances->OrderStatusName($order);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use App\Helpers\Helper;
|
|
||||||
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;
|
|
||||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class controls file related actions related
|
|
||||||
* to assets for the Snipe-IT Asset Management application.
|
|
||||||
*
|
|
||||||
* Based on the Assets/AssetFilesController by A. Gianotto <snipe@snipe.net>
|
|
||||||
*
|
|
||||||
* @version v1.0
|
|
||||||
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
|
||||||
*/
|
|
||||||
class AssetModelFilesController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Accepts a POST to upload a file to the server.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\UploadFileRequest $request
|
|
||||||
* @param int $assetModelId
|
|
||||||
* @since [v7.0.12]
|
|
||||||
* @author [r-xyz]
|
|
||||||
*/
|
|
||||||
public function store(UploadFileRequest $request, $assetModelId = null) : JsonResponse
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we are allowed to update this asset
|
|
||||||
$this->authorize('update', $assetModel);
|
|
||||||
|
|
||||||
if ($request->hasFile('file')) {
|
|
||||||
// If the file storage directory doesn't exist; create it
|
|
||||||
if (! Storage::exists('private_uploads/assetmodels')) {
|
|
||||||
Storage::makeDirectory('private_uploads/assetmodels', 775);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop over the attached files and add them to the asset
|
|
||||||
foreach ($request->file('file') as $file) {
|
|
||||||
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$assetModel->id, $file);
|
|
||||||
|
|
||||||
$assetModel->logUpload($file_name, e($request->get('notes')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done - report success
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $assetModel, trans('admin/models/message.upload.success')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only reach here if no files were included in the POST, so tell the user this
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.upload.nofiles')), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List the files for an asset.
|
|
||||||
*
|
|
||||||
* @param int $assetmodel
|
|
||||||
* @since [v7.0.12]
|
|
||||||
* @author [r-xyz]
|
|
||||||
*/
|
|
||||||
public function list($assetmodel_id) : JsonResponse | array
|
|
||||||
{
|
|
||||||
// Start by checking if the asset being acted upon exists
|
|
||||||
if (! $assetModel = AssetModel::find($assetmodel_id)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$assetmodel = AssetModel::with('uploads')->find($assetmodel_id);
|
|
||||||
$this->authorize('view', $assetmodel);
|
|
||||||
return (new AssetModelsTransformer)->transformAssetModelFiles($assetmodel, $assetmodel->uploads()->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for permissions and display the file.
|
|
||||||
*
|
|
||||||
* @param int $assetModelId
|
|
||||||
* @param int $fileId
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v7.0.12]
|
|
||||||
* @author [r-xyz]
|
|
||||||
*/
|
|
||||||
public function show($assetModelId = null, $fileId = null) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
|
||||||
{
|
|
||||||
// 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 the file being requested exists for the asset
|
|
||||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $assetModel->id)->find($fileId)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.no_match', ['id' => $fileId])), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Form the full filename with path
|
|
||||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
|
||||||
Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
if ($log->action_type == 'audit') {
|
|
||||||
$file = 'private_uploads/audits/'.$log->filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the file actually exists on the filesystem
|
|
||||||
if (! Storage::exists($file)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.does_not_exist', ['id' => $fileId])), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request('inline') == 'true') {
|
|
||||||
|
|
||||||
$headers = [
|
|
||||||
'Content-Disposition' => 'inline',
|
|
||||||
];
|
|
||||||
|
|
||||||
return Storage::download($file, $log->filename, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return StorageHelper::downloader($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send back an error message
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.download.error', ['id' => $fileId])), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the associated file
|
|
||||||
*
|
|
||||||
* @param int $assetModelId
|
|
||||||
* @param int $fileId
|
|
||||||
* @since [v7.0.12]
|
|
||||||
* @author [r-xyz]
|
|
||||||
*/
|
|
||||||
public function destroy($assetModelId = null, $fileId = null) : JsonResponse
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rel_path = 'private_uploads/assetmodels';
|
|
||||||
|
|
||||||
// the asset is valid
|
|
||||||
if (isset($assetModel->id)) {
|
|
||||||
$this->authorize('update', $assetModel);
|
|
||||||
|
|
||||||
// Check for the file
|
|
||||||
$log = Actionlog::find($fileId);
|
|
||||||
if ($log) {
|
|
||||||
// Check the file actually exists, and delete it
|
|
||||||
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
|
||||||
Storage::delete($rel_path.'/'.$log->filename);
|
|
||||||
}
|
|
||||||
// Delete the record of the file
|
|
||||||
$log->delete();
|
|
||||||
|
|
||||||
// All deleting done - notify the user of success
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/models/message.deletefile.success')), 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The file doesn't seem to really exist, so report an error
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.deletefile.error')), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.deletefile.error')), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -85,6 +85,12 @@ class AssetModelsController extends Controller
|
|||||||
$assetmodels = $assetmodels->where('models.model_number', '=', $request->input('model_number'));
|
$assetmodels = $assetmodels->where('models.model_number', '=', $request->input('model_number'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->input('requestable') == 'true') {
|
||||||
|
$assetmodels = $assetmodels->where('models.requestable', '=', '1');
|
||||||
|
} elseif ($request->input('requestable') == 'false') {
|
||||||
|
$assetmodels = $assetmodels->where('models.requestable', '=', '0');
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('notes')) {
|
if ($request->filled('notes')) {
|
||||||
$assetmodels = $assetmodels->where('models.notes', '=', $request->input('notes'));
|
$assetmodels = $assetmodels->where('models.notes', '=', $request->input('notes'));
|
||||||
}
|
}
|
||||||
@@ -148,7 +154,7 @@ class AssetModelsController extends Controller
|
|||||||
$assetmodel = $request->handleImages($assetmodel);
|
$assetmodel = $request->handleImages($assetmodel);
|
||||||
|
|
||||||
if ($assetmodel->save()) {
|
if ($assetmodel->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.create.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new AssetModelsTransformer)->transformAssetModel($assetmodel), trans('admin/models/message.create.success')));
|
||||||
}
|
}
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
|
||||||
|
|
||||||
@@ -201,7 +207,7 @@ class AssetModelsController extends Controller
|
|||||||
$assetmodel = AssetModel::findOrFail($id);
|
$assetmodel = AssetModel::findOrFail($id);
|
||||||
$assetmodel->fill($request->all());
|
$assetmodel->fill($request->all());
|
||||||
$assetmodel = $request->handleImages($assetmodel);
|
$assetmodel = $request->handleImages($assetmodel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow custom_fieldset_id to override and populate fieldset_id.
|
* Allow custom_fieldset_id to override and populate fieldset_id.
|
||||||
* This is stupid, but required for legacy API support.
|
* This is stupid, but required for legacy API support.
|
||||||
@@ -216,7 +222,7 @@ class AssetModelsController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if ($assetmodel->save()) {
|
if ($assetmodel->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new AssetModelsTransformer)->transformAssetModel($assetmodel), trans('admin/models/message.update.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ class AssetsController extends Controller
|
|||||||
'byod',
|
'byod',
|
||||||
'asset_eol_date',
|
'asset_eol_date',
|
||||||
'requestable',
|
'requestable',
|
||||||
|
'jobtitle',
|
||||||
];
|
];
|
||||||
|
|
||||||
$filter = [];
|
$filter = [];
|
||||||
@@ -395,6 +396,9 @@ class AssetsController extends Controller
|
|||||||
case 'assigned_to':
|
case 'assigned_to':
|
||||||
$assets->OrderAssigned($order);
|
$assets->OrderAssigned($order);
|
||||||
break;
|
break;
|
||||||
|
case 'jobtitle':
|
||||||
|
$assets->OrderByJobTitle($order);
|
||||||
|
break;
|
||||||
case 'created_by':
|
case 'created_by':
|
||||||
$assets->OrderByCreatedByName($order);
|
$assets->OrderByCreatedByName($order);
|
||||||
break;
|
break;
|
||||||
@@ -1141,12 +1145,12 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate custom fields
|
// Invoke the validation to see if the audit will complete successfully
|
||||||
Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate();
|
$asset->setRules($asset->getRules() + $asset->customFieldValidationRules());
|
||||||
|
|
||||||
// Validate the rest of the data before we turn off the event dispatcher
|
// Validate the rest of the data before we turn off the event dispatcher
|
||||||
if ($asset->isInvalid()) {
|
if ($asset->isInvalid()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag' => $asset->asset_tag], $asset->getErrors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class CategoriesController extends Controller
|
|||||||
'notes',
|
'notes',
|
||||||
])
|
])
|
||||||
->with('adminuser')
|
->with('adminuser')
|
||||||
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
|
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count');
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -212,7 +212,7 @@ class CategoriesController extends Controller
|
|||||||
public function destroy($id) : JsonResponse
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Category::class);
|
$this->authorize('delete', Category::class);
|
||||||
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count')->findOrFail($id);
|
||||||
|
|
||||||
if (! $category->isDeletable()) {
|
if (! $category->isDeletable()) {
|
||||||
return response()->json(
|
return response()->json(
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ class CompaniesController extends Controller
|
|||||||
|
|
||||||
$companies = Company::withCount(['assets as assets_count' => function ($query) {
|
$companies = Company::withCount(['assets as assets_count' => function ($query) {
|
||||||
$query->AssetsForShow();
|
$query->AssetsForShow();
|
||||||
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
}])
|
||||||
|
->with('adminuser')
|
||||||
|
->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$companies->TextSearch($request->input('search'));
|
$companies->TextSearch($request->input('search'));
|
||||||
@@ -119,6 +122,7 @@ class CompaniesController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('view', Company::class);
|
$this->authorize('view', Company::class);
|
||||||
$company = Company::findOrFail($id);
|
$company = Company::findOrFail($id);
|
||||||
|
$this->authorize('view', $company);
|
||||||
return (new CompaniesTransformer)->transformCompany($company);
|
return (new CompaniesTransformer)->transformCompany($company);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -136,6 +140,7 @@ class CompaniesController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('update', Company::class);
|
$this->authorize('update', Company::class);
|
||||||
$company = Company::findOrFail($id);
|
$company = Company::findOrFail($id);
|
||||||
|
$this->authorize('update', $company);
|
||||||
$company->fill($request->all());
|
$company->fill($request->all());
|
||||||
$company = $request->handleImages($company);
|
$company = $request->handleImages($company);
|
||||||
|
|
||||||
@@ -188,6 +193,7 @@ class CompaniesController extends Controller
|
|||||||
'companies.image',
|
'companies.image',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->get('search').'%');
|
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->get('search').'%');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,6 +234,15 @@ class ImportController extends Controller
|
|||||||
case 'location':
|
case 'location':
|
||||||
$redirectTo = 'locations.index';
|
$redirectTo = 'locations.index';
|
||||||
break;
|
break;
|
||||||
|
case 'supplier':
|
||||||
|
$redirectTo = 'suppliers.index';
|
||||||
|
break;
|
||||||
|
case 'manufacturer':
|
||||||
|
$redirectTo = 'manufacturers.index';
|
||||||
|
break;
|
||||||
|
case 'category':
|
||||||
|
$redirectTo = 'categories.index';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($errors) { //Failure
|
if ($errors) { //Failure
|
||||||
|
|||||||
@@ -29,6 +29,15 @@ class LicenseSeatsController extends Controller
|
|||||||
$seats = LicenseSeat::with('license', 'user', 'asset', 'user.department')
|
$seats = LicenseSeat::with('license', 'user', 'asset', 'user.department')
|
||||||
->where('license_seats.license_id', $licenseId);
|
->where('license_seats.license_id', $licenseId);
|
||||||
|
|
||||||
|
if ($request->input('status') == 'available') {
|
||||||
|
$seats->whereNull('license_seats.assigned_to');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->input('status') == 'assigned') {
|
||||||
|
$seats->ByAssigned();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($request->input('sort') == 'department') {
|
if ($request->input('sort') == 'department') {
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ class LocationsController extends Controller
|
|||||||
->withCount('accessories as accessories_count')
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count');
|
->withCount('users as users_count')
|
||||||
|
->with('adminuser');
|
||||||
|
|
||||||
// Only scope locations if the setting is enabled
|
// Only scope locations if the setting is enabled
|
||||||
if (Setting::getSettings()->scope_locations_fmcs) {
|
if (Setting::getSettings()->scope_locations_fmcs) {
|
||||||
@@ -218,6 +219,7 @@ class LocationsController extends Controller
|
|||||||
'locations.updated_at',
|
'locations.updated_at',
|
||||||
'locations.image',
|
'locations.image',
|
||||||
'locations.currency',
|
'locations.currency',
|
||||||
|
'locations.company_id',
|
||||||
'locations.notes',
|
'locations.notes',
|
||||||
])
|
])
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
|
|||||||
@@ -4,15 +4,19 @@ namespace App\Http\Controllers\Api;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Transformers\ProfileTransformer;
|
||||||
use App\Models\CheckoutRequest;
|
use App\Models\CheckoutRequest;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Laravel\Passport\TokenRepository;
|
use Laravel\Passport\TokenRepository;
|
||||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
class ProfileController extends Controller
|
class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
@@ -167,6 +171,22 @@ class ProfileController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the EULAs accepted by the user.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Transformers\ActionlogsTransformer $transformer
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*@since [v8.1.16]
|
||||||
|
* @author [Godfrey Martinez] [<gmartinez@grokability.com>]
|
||||||
|
*/
|
||||||
|
public function eulas(ProfileTransformer $transformer)
|
||||||
|
{
|
||||||
|
// Only return this user's EULAs
|
||||||
|
$eulas = auth()->user()->eulas;
|
||||||
|
return response()->json(
|
||||||
|
$transformer->transformFiles($eulas, $eulas->count())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,15 @@ class SuppliersController extends Controller
|
|||||||
public function index(Request $request): array
|
public function index(Request $request): array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Supplier::class);
|
$this->authorize('view', Supplier::class);
|
||||||
$allowed_columns = ['
|
$allowed_columns = [
|
||||||
id',
|
'id',
|
||||||
'name',
|
'name',
|
||||||
'address',
|
'address',
|
||||||
|
'address2',
|
||||||
|
'city',
|
||||||
|
'state',
|
||||||
|
'country',
|
||||||
|
'zip',
|
||||||
'phone',
|
'phone',
|
||||||
'contact',
|
'contact',
|
||||||
'fax',
|
'fax',
|
||||||
@@ -39,21 +44,24 @@ class SuppliersController extends Controller
|
|||||||
'components_count',
|
'components_count',
|
||||||
'consumables_count',
|
'consumables_count',
|
||||||
'url',
|
'url',
|
||||||
|
'notes',
|
||||||
];
|
];
|
||||||
|
|
||||||
$suppliers = Supplier::select(
|
$suppliers = Supplier::select(
|
||||||
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'updated_at', 'deleted_at', 'image', 'notes', 'url'])
|
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'created_by', 'updated_at', 'deleted_at', 'image', 'notes', 'url', 'zip'])
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
->withCount('licenses as licenses_count')
|
->withCount('licenses as licenses_count')
|
||||||
->withCount('accessories as accessories_count')
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('components as components_count')
|
->withCount('components as components_count')
|
||||||
->withCount('consumables as consumables_count');
|
->withCount('consumables as consumables_count')
|
||||||
|
->with('adminuser');
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$suppliers = $suppliers->TextSearch($request->input('search'));
|
$suppliers->TextSearch($request->input('search'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('name')) {
|
if ($request->filled('name')) {
|
||||||
$suppliers->where('name', '=', $request->input('name'));
|
$suppliers->where('name', '=', $request->input('name'));
|
||||||
}
|
}
|
||||||
@@ -100,7 +108,15 @@ class SuppliersController extends Controller
|
|||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||||
$suppliers->orderBy($sort, $order);
|
|
||||||
|
switch ($request->input('sort')) {
|
||||||
|
case 'created_by':
|
||||||
|
$suppliers->OrderByCreatedByName($order);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$suppliers->orderBy($sort, $order);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$total = $suppliers->count();
|
$total = $suppliers->count();
|
||||||
$suppliers = $suppliers->skip($offset)->take($limit)->get();
|
$suppliers = $suppliers->skip($offset)->take($limit)->get();
|
||||||
|
|||||||
258
app/Http/Controllers/Api/UploadedFilesController.php
Normal file
258
app/Http/Controllers/Api/UploadedFilesController.php
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Helpers\StorageHelper;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\UploadFileRequest;
|
||||||
|
use App\Http\Transformers\UploadedFilesTransformer;
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\AssetModel;
|
||||||
|
use App\Models\Component;
|
||||||
|
use App\Models\Consumable;
|
||||||
|
use App\Models\License;
|
||||||
|
use App\Models\Location;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
|
||||||
|
class UploadedFilesController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
static $map_object_type = [
|
||||||
|
'accessories' => Accessory::class,
|
||||||
|
'assets' => Asset::class,
|
||||||
|
'components' => Component::class,
|
||||||
|
'consumables' => Consumable::class,
|
||||||
|
'hardware' => Asset::class,
|
||||||
|
'licenses' => License::class,
|
||||||
|
'locations' => Location::class,
|
||||||
|
'models' => AssetModel::class,
|
||||||
|
'users' => User::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
static $map_storage_path = [
|
||||||
|
'accessories' => 'private_uploads/accessories/',
|
||||||
|
'assets' => 'private_uploads/assets/',
|
||||||
|
'components' => 'private_uploads/components/',
|
||||||
|
'consumables' => 'private_uploads/consumables/',
|
||||||
|
'hardware' => 'private_uploads/assets/',
|
||||||
|
'licenses' => 'private_uploads/licenses/',
|
||||||
|
'locations' => 'private_uploads/locations/',
|
||||||
|
'models' => 'private_uploads/assetmodels/',
|
||||||
|
'users' => 'private_uploads/users/',
|
||||||
|
];
|
||||||
|
|
||||||
|
static $map_file_prefix= [
|
||||||
|
'accessories' => 'accessory',
|
||||||
|
'assets' => 'asset',
|
||||||
|
'components' => 'component',
|
||||||
|
'consumables' => 'consumable',
|
||||||
|
'hardware' => 'asset',
|
||||||
|
'licenses' => 'license',
|
||||||
|
'locations' => 'location',
|
||||||
|
'models' => 'model',
|
||||||
|
'users' => 'user',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List files for an object
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param string $object_type the type of object to upload the file to
|
||||||
|
* @param int $id the ID of the object to list files for
|
||||||
|
* @since [v8.1.17]
|
||||||
|
* @author [A. Gianotto <snipe@snipe.net>]
|
||||||
|
*/
|
||||||
|
public function index(Request $request, $object_type, $id) : JsonResponse | array
|
||||||
|
{
|
||||||
|
|
||||||
|
// Check the permissions to make sure the user can view the object
|
||||||
|
$object = self::$map_object_type[$object_type]::find($id);
|
||||||
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
|
if (!$object) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns allowed for sorting
|
||||||
|
$allowed_columns =
|
||||||
|
[
|
||||||
|
'id',
|
||||||
|
'filename',
|
||||||
|
'action_type',
|
||||||
|
'note',
|
||||||
|
'created_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
$uploads = $object->uploads();
|
||||||
|
$offset = ($request->input('offset') > $object->count()) ? $object->count() : abs($request->input('offset'));
|
||||||
|
$limit = app('api_limit_value');
|
||||||
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'action_logs.created_at';
|
||||||
|
|
||||||
|
// Text search on action_logs fields
|
||||||
|
// We could use the normal Actionlogs text scope, but it's a very heavy query since it's searcghing across all relations
|
||||||
|
// And we generally won't need that here
|
||||||
|
if ($request->filled('search')) {
|
||||||
|
|
||||||
|
$uploads->where(
|
||||||
|
function ($query) use ($request) {
|
||||||
|
$query->where('filename', 'LIKE', '%' . $request->input('search') . '%')
|
||||||
|
->orWhere('note', 'LIKE', '%' . $request->input('search') . '%');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploads = $uploads->skip($offset)->take($limit)->orderBy($sort, $order)->get();
|
||||||
|
return (new UploadedFilesTransformer())->transformFiles($uploads, $uploads->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a POST to upload a file to the server.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param string $object_type the type of object to upload the file to
|
||||||
|
* @param int $id the ID of the object to store so we can check permisisons
|
||||||
|
* @since [v8.1.17]
|
||||||
|
* @author [A. Gianotto <snipe@snipe.net>]
|
||||||
|
*/
|
||||||
|
public function store(UploadFileRequest $request, $object_type, $id) : JsonResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
// Check the permissions to make sure the user can view the object
|
||||||
|
$object = self::$map_object_type[$object_type]::find($id);
|
||||||
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
|
if (!$object) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file storage directory doesn't exist, create it
|
||||||
|
if (! Storage::exists(self::$map_storage_path[$object_type])) {
|
||||||
|
Storage::makeDirectory(self::$map_storage_path[$object_type], 775);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->hasFile('file')) {
|
||||||
|
// Loop over the attached files and add them to the object
|
||||||
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile(self::$map_storage_path[$object_type], self::$map_file_prefix[$object_type].'-'.$object->id, $file);
|
||||||
|
$files[] = $file_name;
|
||||||
|
$object->logUpload($file_name, $request->get('notes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
|
||||||
|
->where('item_type', '=', self::$map_object_type[$object_type])
|
||||||
|
->where('item_id', '=', $id)->whereIn('filename', $files)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', (new UploadedFilesTransformer())->transformFiles($files, count($files)), trans_choice('general.file_upload_status.upload.success', count($files))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// No files were submitted
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.nofiles')));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for permissions and display the file.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param string $object_type the type of object to upload the file to
|
||||||
|
* @param int $id the ID of the object to delete from so we can check permisisons
|
||||||
|
* @param $file_id the ID of the file to delete from the action_logs table
|
||||||
|
* @since [v8.1.17]
|
||||||
|
* @author [A. Gianotto <snipe@snipe.net>]
|
||||||
|
*/
|
||||||
|
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
||||||
|
{
|
||||||
|
// Check the permissions to make sure the user can view the object
|
||||||
|
$object = self::$map_object_type[$object_type]::find($id);
|
||||||
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
|
if (!$object) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check that the file being requested exists for the object
|
||||||
|
if (! $log = Actionlog::whereNotNull('filename')->where('item_type', self::$map_object_type[$object_type])->where('item_id', $object->id)->find($file_id)
|
||||||
|
) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_id')), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (! Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.file_not_found'), 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request('inline') == 'true') {
|
||||||
|
$headers = [
|
||||||
|
'Content-Disposition' => 'inline',
|
||||||
|
];
|
||||||
|
return Storage::download(self::$map_storage_path[$object_type].'/'.$log->filename, $log->filename, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StorageHelper::downloader(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the associated file
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param string $object_type the type of object to upload the file to
|
||||||
|
* @param int $id the ID of the object to delete from so we can check permisisons
|
||||||
|
* @param $file_id the ID of the file to delete from the action_logs table
|
||||||
|
* @since [v8.1.17]
|
||||||
|
* @author [A. Gianotto <snipe@snipe.net>]
|
||||||
|
*/
|
||||||
|
public function destroy($object_type, $id, $file_id) : JsonResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
// Check the permissions to make sure the user can view the object
|
||||||
|
$object = self::$map_object_type[$object_type]::find($id);
|
||||||
|
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||||
|
|
||||||
|
if (!$object) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check for the file
|
||||||
|
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
|
||||||
|
->where('item_id', $object->id)->first();
|
||||||
|
|
||||||
|
if ($log) {
|
||||||
|
// Check the file actually exists, and delete it
|
||||||
|
if (Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) {
|
||||||
|
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||||
|
}
|
||||||
|
// Delete the record of the file
|
||||||
|
if ($log->delete()) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The file doesn't seem to really exist, so report an error
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans_choice('general.file_upload_status.delete.error', 1)), 500);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ use App\Helpers\Helper;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\SaveUserRequest;
|
use App\Http\Requests\SaveUserRequest;
|
||||||
use App\Http\Transformers\AccessoriesTransformer;
|
use App\Http\Transformers\AccessoriesTransformer;
|
||||||
|
use App\Http\Transformers\ActionlogsTransformer;
|
||||||
use App\Http\Transformers\AssetsTransformer;
|
use App\Http\Transformers\AssetsTransformer;
|
||||||
use App\Http\Transformers\ConsumablesTransformer;
|
use App\Http\Transformers\ConsumablesTransformer;
|
||||||
use App\Http\Transformers\LicensesTransformer;
|
use App\Http\Transformers\LicensesTransformer;
|
||||||
@@ -80,7 +81,7 @@ class UsersController extends Controller
|
|||||||
'users.autoassign_licenses',
|
'users.autoassign_licenses',
|
||||||
'users.website',
|
'users.website',
|
||||||
|
|
||||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations')
|
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations', 'eulas')
|
||||||
->withCount([
|
->withCount([
|
||||||
'assets as assets_count' => function(Builder $query) {
|
'assets as assets_count' => function(Builder $query) {
|
||||||
$query->withoutTrashed();
|
$query->withoutTrashed();
|
||||||
@@ -206,11 +207,11 @@ class UsersController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('manages_users_count')) {
|
if ($request->filled('manages_users_count')) {
|
||||||
$users->has('manages_users_count', '=', $request->input('manages_users_count'));
|
$users->has('managesUsers', '=', $request->input('manages_users_count'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('manages_locations_count')) {
|
if ($request->filled('manages_locations_count')) {
|
||||||
$users->has('manages_locations_count', '=', $request->input('manages_locations_count'));
|
$users->has('managedLocations', '=', $request->input('manages_locations_count'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('autoassign_licenses')) {
|
if ($request->filled('autoassign_licenses')) {
|
||||||
@@ -676,7 +677,6 @@ class UsersController extends Controller
|
|||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
|
||||||
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
||||||
$this->authorize('update', $user);
|
|
||||||
$licenses = $user->licenses()->get();
|
$licenses = $user->licenses()->get();
|
||||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||||
}
|
}
|
||||||
@@ -736,6 +736,25 @@ class UsersController extends Controller
|
|||||||
return (new UsersTransformer)->transformUser($request->user());
|
return (new UsersTransformer)->transformUser($request->user());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the EULAs accepted by the user.
|
||||||
|
*
|
||||||
|
* @param \App\Models\User $user
|
||||||
|
* @param \App\Http\Transformers\ActionlogsTransformer $transformer
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*@since [v8.1.16]
|
||||||
|
* @author [Godfrey Martinez] [<gmartinez@grokability.com>]
|
||||||
|
*/
|
||||||
|
public function eulas(User $user, ActionlogsTransformer $transformer)
|
||||||
|
{
|
||||||
|
$this->authorize('view', User::class);
|
||||||
|
|
||||||
|
$eulas = $user->eulas;
|
||||||
|
return response()->json(
|
||||||
|
$transformer->transformActionlogs($eulas, $eulas->count())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore a soft-deleted user.
|
* Restore a soft-deleted user.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,19 +19,6 @@ use \Illuminate\Http\RedirectResponse;
|
|||||||
*/
|
*/
|
||||||
class AssetMaintenancesController extends Controller
|
class AssetMaintenancesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Checks for permissions for this action.
|
|
||||||
*
|
|
||||||
* @todo This should be replaced with middleware and/or policies
|
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
|
||||||
* @version v1.0
|
|
||||||
* @since [v1.8]
|
|
||||||
*/
|
|
||||||
private static function getInsufficientPermissionsRedirect(): RedirectResponse
|
|
||||||
{
|
|
||||||
return redirect()->route('maintenances.index')
|
|
||||||
->with('error', trans('general.insufficient_permissions'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view that invokes the ajax tables which actually contains
|
* Returns a view that invokes the ajax tables which actually contains
|
||||||
@@ -67,16 +54,10 @@ class AssetMaintenancesController extends Controller
|
|||||||
// We have to set this so that the correct property is set in the select2 ajax dropdown
|
// We have to set this so that the correct property is set in the select2 ajax dropdown
|
||||||
$asset->asset_id = $asset->id;
|
$asset->asset_id = $asset->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare Asset Maintenance Type List
|
|
||||||
$assetMaintenanceType = [
|
|
||||||
'' => 'Select an asset maintenance type',
|
|
||||||
] + AssetMaintenance::getImprovementOptions();
|
|
||||||
// Mark the selected asset, if it came in
|
|
||||||
|
|
||||||
return view('asset_maintenances/edit')
|
return view('asset_maintenances/edit')
|
||||||
|
->with('assetMaintenanceType', AssetMaintenance::getImprovementOptions())
|
||||||
->with('asset', $asset)
|
->with('asset', $asset)
|
||||||
->with('assetMaintenanceType', $assetMaintenanceType)
|
|
||||||
->with('item', new AssetMaintenance);
|
->with('item', new AssetMaintenance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,43 +72,45 @@ class AssetMaintenancesController extends Controller
|
|||||||
public function store(Request $request) : RedirectResponse
|
public function store(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// create a new model instance
|
|
||||||
$assetMaintenance = new AssetMaintenance();
|
|
||||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
|
||||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
|
||||||
$assetMaintenance->cost = $request->input('cost');
|
|
||||||
$assetMaintenance->notes = $request->input('notes');
|
|
||||||
$asset = Asset::find($request->input('asset_id'));
|
|
||||||
|
|
||||||
if ((! Company::isCurrentUserHasAccess($asset)) && ($asset != null)) {
|
$assets = Asset::whereIn('id', $request->input('selected_assets'))->get();
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
|
// Loop through the selected assets
|
||||||
|
foreach ($assets as $asset) {
|
||||||
|
|
||||||
|
$assetMaintenance = new AssetMaintenance();
|
||||||
|
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||||
|
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||||
|
$assetMaintenance->cost = $request->input('cost');
|
||||||
|
$assetMaintenance->notes = $request->input('notes');
|
||||||
|
|
||||||
|
// Save the asset maintenance data
|
||||||
|
$assetMaintenance->asset_id = $asset->id;
|
||||||
|
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||||
|
$assetMaintenance->title = $request->input('title');
|
||||||
|
$assetMaintenance->start_date = $request->input('start_date');
|
||||||
|
$assetMaintenance->completion_date = $request->input('completion_date');
|
||||||
|
$assetMaintenance->created_by = auth()->id();
|
||||||
|
|
||||||
|
if (($assetMaintenance->completion_date !== null)
|
||||||
|
&& ($assetMaintenance->start_date !== '')
|
||||||
|
&& ($assetMaintenance->start_date !== '0000-00-00')
|
||||||
|
) {
|
||||||
|
$startDate = Carbon::parse($assetMaintenance->start_date);
|
||||||
|
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
||||||
|
$assetMaintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Was the asset maintenance created?
|
||||||
|
if (!$assetMaintenance->save()) {
|
||||||
|
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the asset maintenance data
|
return redirect()->route('maintenances.index')
|
||||||
$assetMaintenance->asset_id = $request->input('asset_id');
|
->with('success', trans('admin/asset_maintenances/message.create.success'));
|
||||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
|
||||||
$assetMaintenance->title = $request->input('title');
|
|
||||||
$assetMaintenance->start_date = $request->input('start_date');
|
|
||||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
|
||||||
$assetMaintenance->created_by = auth()->id();
|
|
||||||
|
|
||||||
if (($assetMaintenance->completion_date !== null)
|
|
||||||
&& ($assetMaintenance->start_date !== '')
|
|
||||||
&& ($assetMaintenance->start_date !== '0000-00-00')
|
|
||||||
) {
|
|
||||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
|
||||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
|
||||||
$assetMaintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Was the asset maintenance created?
|
|
||||||
if ($assetMaintenance->save()) {
|
|
||||||
// Redirect to the new asset maintenance page
|
|
||||||
return redirect()->route('maintenances.index')
|
|
||||||
->with('success', trans('admin/asset_maintenances/message.create.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,26 +118,19 @@ class AssetMaintenancesController extends Controller
|
|||||||
*
|
*
|
||||||
* @see AssetMaintenancesController::postEdit() method that stores the data
|
* @see AssetMaintenancesController::postEdit() method that stores the data
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @param int $assetMaintenanceId
|
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
*/
|
*/
|
||||||
public function edit(AssetMaintenance $maintenance) : View | RedirectResponse
|
public function edit(AssetMaintenance $maintenance) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
if ((!$maintenance->asset) || ($maintenance->asset->deleted_at!='')) {
|
$this->authorize('update', $maintenance->asset);
|
||||||
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
|
||||||
} elseif (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare Improvement Type List
|
|
||||||
$assetMaintenanceType = ['' => 'Select an improvement type'] + AssetMaintenance::getImprovementOptions();
|
|
||||||
|
|
||||||
return view('asset_maintenances/edit')
|
return view('asset_maintenances/edit')
|
||||||
->with('selectedAsset', null)
|
->with('selected_assets', $maintenance->asset->pluck('id')->toArray())
|
||||||
->with('assetMaintenanceType', $assetMaintenanceType)
|
->with('asset_ids', request()->input('asset_ids', []))
|
||||||
->with('item', $maintenance);
|
->with('assetMaintenanceType', AssetMaintenance::getImprovementOptions())
|
||||||
|
->with('item', $maintenance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,33 +146,21 @@ class AssetMaintenancesController extends Controller
|
|||||||
public function update(Request $request, AssetMaintenance $maintenance) : View | RedirectResponse
|
public function update(Request $request, AssetMaintenance $maintenance) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
|
$this->authorize('update', $maintenance->asset);
|
||||||
if ((!$maintenance->asset) || ($maintenance->asset->deleted_at!='')) {
|
|
||||||
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
|
||||||
} elseif (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
$maintenance->supplier_id = $request->input('supplier_id');
|
$maintenance->supplier_id = $request->input('supplier_id');
|
||||||
$maintenance->is_warranty = $request->input('is_warranty');
|
$maintenance->is_warranty = $request->input('is_warranty', 0);
|
||||||
$maintenance->cost = $request->input('cost');
|
$maintenance->cost = $request->input('cost');
|
||||||
$maintenance->notes = $request->input('notes');
|
$maintenance->notes = $request->input('notes');
|
||||||
|
|
||||||
$asset = Asset::find(request('asset_id'));
|
|
||||||
|
|
||||||
if (! Company::isCurrentUserHasAccess($asset)) {
|
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the asset maintenance data
|
|
||||||
$maintenance->asset_id = $request->input('asset_id');
|
|
||||||
$maintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
$maintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||||
$maintenance->title = $request->input('title');
|
$maintenance->title = $request->input('title');
|
||||||
$maintenance->start_date = $request->input('start_date');
|
$maintenance->start_date = $request->input('start_date');
|
||||||
$maintenance->completion_date = $request->input('completion_date');
|
$maintenance->completion_date = $request->input('completion_date');
|
||||||
|
|
||||||
if (($maintenance->completion_date == null)
|
|
||||||
) {
|
// Todo - put this in a getter/setter?
|
||||||
|
if (($maintenance->completion_date == null))
|
||||||
|
{
|
||||||
if (($maintenance->asset_maintenance_time !== 0)
|
if (($maintenance->asset_maintenance_time !== 0)
|
||||||
|| (! is_null($maintenance->asset_maintenance_time))
|
|| (! is_null($maintenance->asset_maintenance_time))
|
||||||
) {
|
) {
|
||||||
@@ -213,10 +177,7 @@ class AssetMaintenancesController extends Controller
|
|||||||
$maintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
$maintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Was the asset maintenance created?
|
|
||||||
if ($maintenance->save()) {
|
if ($maintenance->save()) {
|
||||||
|
|
||||||
// Redirect to the new asset maintenance page
|
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')
|
||||||
->with('success', trans('admin/asset_maintenances/message.edit.success'));
|
->with('success', trans('admin/asset_maintenances/message.edit.success'));
|
||||||
}
|
}
|
||||||
@@ -232,21 +193,12 @@ class AssetMaintenancesController extends Controller
|
|||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
*/
|
*/
|
||||||
public function destroy($assetMaintenanceId) : RedirectResponse
|
public function destroy(AssetMaintenance $maintenance) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
$this->authorize('update', $maintenance->asset);
|
||||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
|
||||||
// Redirect to the asset maintenance management page
|
|
||||||
return redirect()->route('maintenances.index')
|
|
||||||
->with('error', trans('admin/asset_maintenances/message.not_found'));
|
|
||||||
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the asset maintenance
|
// Delete the asset maintenance
|
||||||
$assetMaintenance->delete();
|
$maintenance->delete();
|
||||||
|
|
||||||
// Redirect to the asset_maintenance management page
|
// Redirect to the asset_maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')
|
||||||
->with('success', trans('admin/asset_maintenances/message.delete.success'));
|
->with('success', trans('admin/asset_maintenances/message.delete.success'));
|
||||||
@@ -262,11 +214,6 @@ class AssetMaintenancesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(AssetMaintenance $maintenance) : View | RedirectResponse
|
public function show(AssetMaintenance $maintenance) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
|
||||||
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
|
||||||
return static::getInsufficientPermissionsRedirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('asset_maintenances/view')->with('assetMaintenance', $maintenance);
|
return view('asset_maintenances/view')->with('assetMaintenance', $maintenance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ class AssetCheckinController extends Controller
|
|||||||
});
|
});
|
||||||
|
|
||||||
$asset->expected_checkin = null;
|
$asset->expected_checkin = null;
|
||||||
$asset->last_checkin = now();
|
|
||||||
$asset->assignedTo()->disassociate($asset);
|
$asset->assignedTo()->disassociate($asset);
|
||||||
$asset->accepted = null;
|
$asset->accepted = null;
|
||||||
$asset->name = $request->get('name');
|
$asset->name = $request->get('name');
|
||||||
@@ -123,11 +122,14 @@ class AssetCheckinController extends Controller
|
|||||||
|
|
||||||
$originalValues = $asset->getRawOriginal();
|
$originalValues = $asset->getRawOriginal();
|
||||||
|
|
||||||
|
// Handle last checkin date
|
||||||
$checkin_at = date('Y-m-d H:i:s');
|
$checkin_at = date('Y-m-d H:i:s');
|
||||||
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
|
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
|
||||||
$originalValues['action_date'] = $checkin_at;
|
$originalValues['action_date'] = $checkin_at;
|
||||||
$checkin_at = $request->get('checkin_at');
|
$checkin_at = $request->get('checkin_at');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
$asset->last_checkin = $checkin_at;
|
||||||
|
|
||||||
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
||||||
$seat->update(['assigned_to' => null]);
|
$seat->update(['assigned_to' => null]);
|
||||||
@@ -151,7 +153,8 @@ class AssetCheckinController extends Controller
|
|||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))->with('success', trans('admin/hardware/message.checkin.success'));
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
|
->with('success', trans('admin/hardware/message.checkin.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class AssetCheckoutController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
->with('success', trans('admin/hardware/message.checkout.success'));
|
->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ class AssetsController extends Controller
|
|||||||
$asset->byod = request('byod', 0);
|
$asset->byod = request('byod', 0);
|
||||||
|
|
||||||
if (! empty($settings->audit_interval)) {
|
if (! empty($settings->audit_interval)) {
|
||||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$asset->next_audit_date = Carbon::now()->addMonths((int) $settings->audit_interval)->toDateString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||||
@@ -188,14 +188,31 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
// Validate the asset before saving
|
// Validate the asset before saving
|
||||||
if ($asset->isValid() && $asset->save()) {
|
if ($asset->isValid() && $asset->save()) {
|
||||||
if (request('assigned_user')) {
|
$target = null;
|
||||||
$target = User::find(request('assigned_user'));
|
$location = null;
|
||||||
|
|
||||||
|
if ($userId = request('assigned_user')) {
|
||||||
|
$target = User::find($userId);
|
||||||
|
|
||||||
|
if (!$target) {
|
||||||
|
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.user'));
|
||||||
|
}
|
||||||
$location = $target->location_id;
|
$location = $target->location_id;
|
||||||
} elseif (request('assigned_asset')) {
|
|
||||||
$target = Asset::find(request('assigned_asset'));
|
} elseif ($assetId = request('assigned_asset')) {
|
||||||
|
$target = Asset::find($assetId);
|
||||||
|
|
||||||
|
if (!$target) {
|
||||||
|
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.asset'));
|
||||||
|
}
|
||||||
$location = $target->location_id;
|
$location = $target->location_id;
|
||||||
} elseif (request('assigned_location')) {
|
|
||||||
$target = Location::find(request('assigned_location'));
|
} elseif ($locationId = request('assigned_location')) {
|
||||||
|
$target = Location::find($locationId);
|
||||||
|
|
||||||
|
if (!$target) {
|
||||||
|
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.location'));
|
||||||
|
}
|
||||||
$location = $target->id;
|
$location = $target->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,18 +233,18 @@ class AssetsController extends Controller
|
|||||||
if ($successes) {
|
if ($successes) {
|
||||||
if ($failures) {
|
if ($failures) {
|
||||||
//some succeeded, some failed
|
//some succeeded, some failed
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets')) //FIXME - not tested
|
return Helper::getRedirectOption($request, $asset->id, 'Assets') //FIXME - not tested
|
||||||
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]))
|
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]))
|
||||||
->with('warning', trans_choice('admin/hardware/message.create.partial_failure', $failures, ['failures' => join("; ", $failures)]));
|
->with('warning', trans_choice('admin/hardware/message.create.partial_failure', $failures, ['failures' => join("; ", $failures)]));
|
||||||
} else {
|
} else {
|
||||||
if (count($successes) == 1) {
|
if (count($successes) == 1) {
|
||||||
//the most common case, keeping it so we don't have to make every use of that translation string be trans_choice'ed
|
//the most common case, keeping it so we don't have to make every use of that translation string be trans_choice'ed
|
||||||
//and re-translated
|
//and re-translated
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset), 'id', 'tag' => e($asset->asset_tag)]));
|
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset), 'id', 'tag' => e($asset->asset_tag)]));
|
||||||
} else {
|
} else {
|
||||||
//multi-success
|
//multi-success
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]));
|
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,6 +265,7 @@ class AssetsController extends Controller
|
|||||||
public function edit(Asset $asset) : View | RedirectResponse
|
public function edit(Asset $asset) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize($asset);
|
$this->authorize($asset);
|
||||||
|
session()->put('back_url', url()->previous());
|
||||||
return view('hardware/edit')
|
return view('hardware/edit')
|
||||||
->with('item', $asset)
|
->with('item', $asset)
|
||||||
->with('statuslabel_list', Helper::statusLabelList())
|
->with('statuslabel_list', Helper::statusLabelList())
|
||||||
@@ -410,11 +428,15 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
session()->put([
|
||||||
|
'redirect_option' => $request->get('redirect_option'),
|
||||||
|
'checkout_to_type' => $request->get('checkout_to_type'),
|
||||||
|
'other_redirect' => $request->get('redirect_option') === 'other_redirect' ? 'model' : null,
|
||||||
|
]);
|
||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
->with('success', trans('admin/hardware/message.update.success'));
|
->with('success', trans('admin/hardware/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +468,7 @@ class AssetsController extends Controller
|
|||||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
|
||||||
DB::table('assets')
|
DB::table('assets')
|
||||||
->where('id', $asset->id)
|
->where('id', $asset->id)
|
||||||
->update(['assigned_to' => null]);
|
->update(['assigned_to' => null, 'assigned_type' => null]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -458,6 +480,7 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset->delete();
|
$asset->delete();
|
||||||
|
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
|
||||||
@@ -890,7 +913,7 @@ class AssetsController extends Controller
|
|||||||
return redirect()->route('hardware.edit', $asset)->withErrors($asset->getErrors());
|
return redirect()->route('hardware.edit', $asset)->withErrors($asset->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$dt = Carbon::now()->addMonths( (int) $settings->audit_interval)->toDateString();
|
||||||
return view('hardware/audit')->with('asset', $asset)->with('item', $asset)->with('next_audit_date', $dt)->with('locations_list');
|
return view('hardware/audit')->with('asset', $asset)->with('item', $asset)->with('next_audit_date', $dt)->with('locations_list');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,8 +960,8 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate custom fields
|
// Invoke the validation to see if the audit will complete successfully
|
||||||
Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate();
|
$asset->setRules($asset->getRules() + $asset->customFieldValidationRules());
|
||||||
|
|
||||||
// Validate the rest of the data before we turn off the event dispatcher
|
// Validate the rest of the data before we turn off the event dispatcher
|
||||||
if ($asset->isInvalid()) {
|
if ($asset->isInvalid()) {
|
||||||
@@ -978,7 +1001,7 @@ class AssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name, $originalValues);
|
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name, $originalValues);
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))->with('success', trans('admin/hardware/message.audit.success'));
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')->with('success', trans('admin/hardware/message.audit.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||||
|
|||||||
@@ -52,11 +52,26 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$asset_ids = $request->input('ids');
|
$asset_ids = $request->input('ids');
|
||||||
|
|
||||||
if ($request->input('bulk_actions') === 'checkout') {
|
if ($request->input('bulk_actions') === 'checkout') {
|
||||||
|
$status_check =$this->hasUndeployableStatus($asset_ids);
|
||||||
|
if($status_check && $status_check['status'] === true){
|
||||||
|
|
||||||
|
$asset_tags = implode(', ', array_column($status_check['tags'], 'asset_tag'));
|
||||||
|
$asset_ids = $status_check['asset_ids'];
|
||||||
|
|
||||||
|
session()->flash('warning', trans('admin/hardware/message.undeployable', ['asset_tags' => $asset_tags]));
|
||||||
|
}
|
||||||
|
|
||||||
$request->session()->flashInput(['selected_assets' => $asset_ids]);
|
$request->session()->flashInput(['selected_assets' => $asset_ids]);
|
||||||
return redirect()->route('hardware.bulkcheckout.show');
|
return redirect()->route('hardware.bulkcheckout.show');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->input('bulk_actions') === 'maintenance') {
|
||||||
|
$request->session()->flashInput(['selected_assets' => $asset_ids]);
|
||||||
|
return redirect()->route('maintenances.create');
|
||||||
|
}
|
||||||
|
|
||||||
// Figure out where we need to send the user after the update is complete, and store that in the session
|
// Figure out where we need to send the user after the update is complete, and store that in the session
|
||||||
$bulk_back_url = request()->headers->get('referer');
|
$bulk_back_url = request()->headers->get('referer');
|
||||||
session(['bulk_back_url' => $bulk_back_url]);
|
session(['bulk_back_url' => $bulk_back_url]);
|
||||||
@@ -97,11 +112,47 @@ class BulkAssetsController extends Controller
|
|||||||
// This handles all of the pivot sorting below (versus the assets.* fields in the allowed_columns array)
|
// This handles all of the pivot sorting below (versus the assets.* fields in the allowed_columns array)
|
||||||
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.id';
|
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.id';
|
||||||
|
|
||||||
$assets = Asset::with('assignedTo', 'location', 'model')
|
$query = Asset::with('assignedTo', 'location', 'model')
|
||||||
->whereIn('assets.id', $asset_ids)
|
->whereIn('assets.id', $asset_ids)
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
|
|
||||||
$assets = $assets->get();
|
|
||||||
|
switch ($sort_override) {
|
||||||
|
case 'model':
|
||||||
|
$query->OrderModels($order);
|
||||||
|
break;
|
||||||
|
case 'model_number':
|
||||||
|
$query->OrderModelNumber($order);
|
||||||
|
break;
|
||||||
|
case 'category':
|
||||||
|
$query->OrderCategory($order);
|
||||||
|
break;
|
||||||
|
case 'manufacturer':
|
||||||
|
$query->OrderManufacturer($order);
|
||||||
|
break;
|
||||||
|
case 'company':
|
||||||
|
$query->OrderCompany($order);
|
||||||
|
break;
|
||||||
|
case 'location':
|
||||||
|
$query->OrderLocation($order);
|
||||||
|
break;
|
||||||
|
case 'rtd_location':
|
||||||
|
$query->OrderRtdLocation($order);
|
||||||
|
break;
|
||||||
|
case 'status_label':
|
||||||
|
$query->OrderStatus($order);
|
||||||
|
break;
|
||||||
|
case 'supplier':
|
||||||
|
$query->OrderSupplier($order);
|
||||||
|
break;
|
||||||
|
case 'assigned_to':
|
||||||
|
$query->OrderAssigned($order);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$query->orderBy($column_sort, $order);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$assets = $query->get();
|
||||||
|
|
||||||
if ($assets->isEmpty()) {
|
if ($assets->isEmpty()) {
|
||||||
Log::debug('No assets were found for the provided IDs', ['ids' => $asset_ids]);
|
Log::debug('No assets were found for the provided IDs', ['ids' => $asset_ids]);
|
||||||
@@ -154,40 +205,7 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($sort_override) {
|
|
||||||
case 'model':
|
|
||||||
$assets->OrderModels($order);
|
|
||||||
break;
|
|
||||||
case 'model_number':
|
|
||||||
$assets->OrderModelNumber($order);
|
|
||||||
break;
|
|
||||||
case 'category':
|
|
||||||
$assets->OrderCategory($order);
|
|
||||||
break;
|
|
||||||
case 'manufacturer':
|
|
||||||
$assets->OrderManufacturer($order);
|
|
||||||
break;
|
|
||||||
case 'company':
|
|
||||||
$assets->OrderCompany($order);
|
|
||||||
break;
|
|
||||||
case 'location':
|
|
||||||
$assets->OrderLocation($order);
|
|
||||||
case 'rtd_location':
|
|
||||||
$assets->OrderRtdLocation($order);
|
|
||||||
break;
|
|
||||||
case 'status_label':
|
|
||||||
$assets->OrderStatus($order);
|
|
||||||
break;
|
|
||||||
case 'supplier':
|
|
||||||
$assets->OrderSupplier($order);
|
|
||||||
break;
|
|
||||||
case 'assigned_to':
|
|
||||||
$assets->OrderAssigned($order);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$assets->orderBy($column_sort, $order);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->back()->with('error', 'No action selected');
|
return redirect()->back()->with('error', 'No action selected');
|
||||||
}
|
}
|
||||||
@@ -214,6 +232,21 @@ class BulkAssetsController extends Controller
|
|||||||
|
|
||||||
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
|
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
|
||||||
|
|
||||||
|
// find custom field input attributes that start with 'null_'
|
||||||
|
$null_custom_fields_inputs = array_filter($request->all(), function ($key) {
|
||||||
|
// filter out all keys that start with 'null_'
|
||||||
|
return (strpos($key, 'null_') === 0);
|
||||||
|
}, ARRAY_FILTER_USE_KEY);;
|
||||||
|
// remove 'null' from the keys
|
||||||
|
$custom_fields_to_null = [];
|
||||||
|
foreach ($null_custom_fields_inputs as $key => $value) {
|
||||||
|
$custom_fields_to_null[str_replace('null', '', $key)] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (! $request->filled('ids') || count($request->input('ids')) == 0) {
|
if (! $request->filled('ids') || count($request->input('ids')) == 0) {
|
||||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||||
@@ -251,7 +284,9 @@ class BulkAssetsController extends Controller
|
|||||||
|| ($request->filled('null_expected_checkin_date'))
|
|| ($request->filled('null_expected_checkin_date'))
|
||||||
|| ($request->filled('null_next_audit_date'))
|
|| ($request->filled('null_next_audit_date'))
|
||||||
|| ($request->filled('null_asset_eol_date'))
|
|| ($request->filled('null_asset_eol_date'))
|
||||||
|
|| ($request->filled('null_notes'))
|
||||||
|| ($request->anyFilled($custom_field_columns))
|
|| ($request->anyFilled($custom_field_columns))
|
||||||
|
|| ($request->anyFilled(array_keys($null_custom_fields_inputs)))
|
||||||
|
|
||||||
) {
|
) {
|
||||||
// Let's loop through those assets and build an update array
|
// Let's loop through those assets and build an update array
|
||||||
@@ -274,10 +309,14 @@ class BulkAssetsController extends Controller
|
|||||||
->conditionallyAddItem('supplier_id')
|
->conditionallyAddItem('supplier_id')
|
||||||
->conditionallyAddItem('warranty_months')
|
->conditionallyAddItem('warranty_months')
|
||||||
->conditionallyAddItem('next_audit_date')
|
->conditionallyAddItem('next_audit_date')
|
||||||
->conditionallyAddItem('asset_eol_date');
|
->conditionallyAddItem('asset_eol_date')
|
||||||
|
->conditionallyAddItem('notes');
|
||||||
foreach ($custom_field_columns as $key => $custom_field_column) {
|
foreach ($custom_field_columns as $key => $custom_field_column) {
|
||||||
$this->conditionallyAddItem($custom_field_column);
|
$this->conditionallyAddItem($custom_field_column);
|
||||||
}
|
}
|
||||||
|
foreach ($custom_fields_to_null as $key => $custom_field_to_null) {
|
||||||
|
$this->conditionallyAddItem($key);
|
||||||
|
}
|
||||||
|
|
||||||
if (!($asset->eol_explicit)) {
|
if (!($asset->eol_explicit)) {
|
||||||
if ($request->filled('model_id')) {
|
if ($request->filled('model_id')) {
|
||||||
@@ -328,6 +367,10 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->input('null_notes')=='1') {
|
||||||
|
$this->update_array['notes'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('purchase_cost')) {
|
if ($request->filled('purchase_cost')) {
|
||||||
@@ -368,10 +411,12 @@ class BulkAssetsController extends Controller
|
|||||||
// This could probably be added to a form request.
|
// This could probably be added to a form request.
|
||||||
// If the asset isn't assigned, we don't care what the status is.
|
// If the asset isn't assigned, we don't care what the status is.
|
||||||
// Otherwise we need to make sure the status type is still a deployable one.
|
// Otherwise we need to make sure the status type is still a deployable one.
|
||||||
if (
|
|
||||||
($asset->assigned_to == '')
|
$unassigned = $asset->assigned_to == '';
|
||||||
|| ($updated_status->deployable == '1') && ($asset->assetstatus?->deployable == '1')
|
$deployable = $updated_status->deployable == '1' && $asset->assetstatus?->deployable == '1';
|
||||||
) {
|
$pending = $updated_status->pending === 1;
|
||||||
|
|
||||||
|
if ($unassigned || $deployable || $pending) {
|
||||||
$this->update_array['status_id'] = $updated_status->id;
|
$this->update_array['status_id'] = $updated_status->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +468,7 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* Start all the custom fields shenanigans
|
* Start all the custom fields shenanigans
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -430,6 +476,15 @@ class BulkAssetsController extends Controller
|
|||||||
if ($asset->model->fieldset) {
|
if ($asset->model->fieldset) {
|
||||||
foreach ($asset->model->fieldset->fields as $field) {
|
foreach ($asset->model->fieldset->fields as $field) {
|
||||||
|
|
||||||
|
// null custom fields
|
||||||
|
if ($custom_fields_to_null) {
|
||||||
|
foreach ($custom_fields_to_null as $key => $custom_field_to_null) {
|
||||||
|
if ($field->db_column == $key) {
|
||||||
|
$this->update_array[$field->db_column] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||||
if (Gate::allows('admin')) {
|
if (Gate::allows('admin')) {
|
||||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||||
@@ -562,7 +617,10 @@ class BulkAssetsController extends Controller
|
|||||||
public function showCheckout() : View
|
public function showCheckout() : View
|
||||||
{
|
{
|
||||||
$this->authorize('checkout', Asset::class);
|
$this->authorize('checkout', Asset::class);
|
||||||
return view('hardware/bulk-checkout');
|
|
||||||
|
$do_not_change = ['' => trans('general.do_not_change')];
|
||||||
|
$status_label_list = $do_not_change + Helper::deployableStatusLabelList();
|
||||||
|
return view('hardware/bulk-checkout')->with('statusLabel_list', $status_label_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -594,13 +652,13 @@ class BulkAssetsController extends Controller
|
|||||||
}
|
}
|
||||||
$checkout_at = date('Y-m-d H:i:s');
|
$checkout_at = date('Y-m-d H:i:s');
|
||||||
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
|
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
|
||||||
$checkout_at = e($request->get('checkout_at'));
|
$checkout_at = $request->get('checkout_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
$expected_checkin = '';
|
$expected_checkin = '';
|
||||||
|
|
||||||
if ($request->filled('expected_checkin')) {
|
if ($request->filled('expected_checkin')) {
|
||||||
$expected_checkin = e($request->get('expected_checkin'));
|
$expected_checkin = $request->get('expected_checkin');
|
||||||
}
|
}
|
||||||
|
|
||||||
$errors = [];
|
$errors = [];
|
||||||
@@ -608,6 +666,11 @@ class BulkAssetsController extends Controller
|
|||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
$this->authorize('checkout', $asset);
|
$this->authorize('checkout', $asset);
|
||||||
|
|
||||||
|
// See if there is a status label passed
|
||||||
|
if ($request->filled('status_id')) {
|
||||||
|
$asset->status_id = $request->get('status_id');
|
||||||
|
}
|
||||||
|
|
||||||
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
|
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
|
||||||
|
|
||||||
//TODO - I think this logic is duplicated in the checkOut method?
|
//TODO - I think this logic is duplicated in the checkOut method?
|
||||||
@@ -651,4 +714,25 @@ class BulkAssetsController extends Controller
|
|||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function hasUndeployableStatus (array $asset_ids)
|
||||||
|
{
|
||||||
|
$undeployable = Asset::whereIn('id', $asset_ids)
|
||||||
|
->undeployable()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$undeployableTags = $undeployable->map(function ($asset) {
|
||||||
|
return [
|
||||||
|
'id' => $asset->id,
|
||||||
|
'asset_tag' => $asset->asset_tag,
|
||||||
|
];
|
||||||
|
})->toArray();
|
||||||
|
|
||||||
|
$undeployableIds = array_column($undeployableTags, 'id');
|
||||||
|
$filtered_ids = array_diff($asset_ids, $undeployableIds);
|
||||||
|
|
||||||
|
if($undeployable->isNotEmpty()) {
|
||||||
|
return ['status' => true, 'tags' => $undeployableTags, 'asset_ids' => $filtered_ids];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class CategoriesController extends Controller
|
|||||||
$category->eula_text = $request->input('eula_text');
|
$category->eula_text = $request->input('eula_text');
|
||||||
$category->use_default_eula = $request->input('use_default_eula', '0');
|
$category->use_default_eula = $request->input('use_default_eula', '0');
|
||||||
$category->require_acceptance = $request->input('require_acceptance', '0');
|
$category->require_acceptance = $request->input('require_acceptance', '0');
|
||||||
|
$category->alert_on_response = $request->input('alert_on_response', '0');
|
||||||
$category->checkin_email = $request->input('checkin_email', '0');
|
$category->checkin_email = $request->input('checkin_email', '0');
|
||||||
$category->notes = $request->input('notes');
|
$category->notes = $request->input('notes');
|
||||||
$category->created_by = auth()->id();
|
$category->created_by = auth()->id();
|
||||||
@@ -121,6 +122,7 @@ class CategoriesController extends Controller
|
|||||||
$category->eula_text = $request->input('eula_text');
|
$category->eula_text = $request->input('eula_text');
|
||||||
$category->use_default_eula = $request->input('use_default_eula', '0');
|
$category->use_default_eula = $request->input('use_default_eula', '0');
|
||||||
$category->require_acceptance = $request->input('require_acceptance', '0');
|
$category->require_acceptance = $request->input('require_acceptance', '0');
|
||||||
|
$category->alert_on_response = $request->input('alert_on_response', '0');
|
||||||
$category->checkin_email = $request->input('checkin_email', '0');
|
$category->checkin_email = $request->input('checkin_email', '0');
|
||||||
$category->notes = $request->input('notes');
|
$category->notes = $request->input('notes');
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ class CategoriesController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('delete', Category::class);
|
$this->authorize('delete', Category::class);
|
||||||
// Check if the category exists
|
// Check if the category exists
|
||||||
if (is_null($category = Category::findOrFail($categoryId))) {
|
if (is_null($category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count')->findOrFail($categoryId))) {
|
||||||
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
|
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +157,6 @@ class CategoriesController extends Controller
|
|||||||
|
|
||||||
Storage::disk('public')->delete('categories'.'/'.$category->image);
|
Storage::disk('public')->delete('categories'.'/'.$category->image);
|
||||||
$category->delete();
|
$category->delete();
|
||||||
// Redirect to the locations management page
|
|
||||||
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success'));
|
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,11 +123,13 @@ final class CompaniesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy($companyId) : RedirectResponse
|
public function destroy($companyId) : RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if (is_null($company = Company::find($companyId))) {
|
if (is_null($company = Company::find($companyId))) {
|
||||||
return redirect()->route('companies.index')
|
return redirect()->route('companies.index')
|
||||||
->with('error', trans('admin/companies/message.not_found'));
|
->with('error', trans('admin/companies/message.not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->authorize('delete', $company);
|
$this->authorize('delete', $company);
|
||||||
if (! $company->isDeletable()) {
|
if (! $company->isDeletable()) {
|
||||||
return redirect()->route('companies.index')
|
return redirect()->route('companies.index')
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ class ComponentCheckinController extends Controller
|
|||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success',
|
return Helper::getRedirectOption($request, $component->id, 'Components')
|
||||||
trans('admin/components/message.checkin.success'));
|
->with('success', trans('admin/components/message.checkin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
|
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class ComponentCheckoutController extends Controller
|
|||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.checkout.success'));
|
return Helper::getRedirectOption($request, $component->id, 'Components')
|
||||||
|
->with('success', trans('admin/components/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ class ComponentsController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($component->save()) {
|
if ($component->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.create.success'));
|
return Helper::getRedirectOption($request, $component->id, 'Components')
|
||||||
|
->with('success', trans('admin/components/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
||||||
@@ -111,6 +112,7 @@ class ComponentsController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('update', $component);
|
$this->authorize('update', $component);
|
||||||
|
session()->put('back_url', url()->previous());
|
||||||
return view('components/edit')
|
return view('components/edit')
|
||||||
->with('item', $component)
|
->with('item', $component)
|
||||||
->with('category_type', 'component');
|
->with('category_type', 'component');
|
||||||
@@ -164,7 +166,8 @@ class ComponentsController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($component->save()) {
|
if ($component->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.update.success'));
|
return Helper::getRedirectOption($request, $component->id, 'Components')
|
||||||
|
->with('success', trans('admin/components/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ class ConsumableCheckoutController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
// Redirect to the new consumable page
|
// Redirect to the new consumable page
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.checkout.success'));
|
return Helper::getRedirectOption($request, $consumable->id, 'Consumables')
|
||||||
|
->with('success', trans('admin/consumables/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ class ConsumablesController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($consumable->save()) {
|
if ($consumable->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.create.success'));
|
return Helper::getRedirectOption($request, $consumable->id, 'Consumables')
|
||||||
|
->with('success', trans('admin/consumables/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
||||||
@@ -107,6 +108,7 @@ class ConsumablesController extends Controller
|
|||||||
public function edit(Consumable $consumable) : View | RedirectResponse
|
public function edit(Consumable $consumable) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize($consumable);
|
$this->authorize($consumable);
|
||||||
|
session()->put('back_url', url()->previous());
|
||||||
return view('consumables/edit')
|
return view('consumables/edit')
|
||||||
->with('item', $consumable)
|
->with('item', $consumable)
|
||||||
->with('category_type', 'consumable');
|
->with('category_type', 'consumable');
|
||||||
@@ -160,7 +162,8 @@ class ConsumablesController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($consumable->save()) {
|
if ($consumable->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.update.success'));
|
return Helper::getRedirectOption($request, $consumable->id, 'Consumables')
|
||||||
|
->with('success', trans('admin/consumables/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class LicenseCheckinController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($licenseSeat->assigned_to != null){
|
if($licenseSeat->assigned_to != null){
|
||||||
$return_to = User::find($licenseSeat->assigned_to);
|
$return_to = User::withTrashed()->find($licenseSeat->assigned_to);
|
||||||
session()->put('checkedInFrom', $return_to->id);
|
session()->put('checkedInFrom', $return_to->id);
|
||||||
} else {
|
} else {
|
||||||
$return_to = Asset::find($licenseSeat->asset_id);
|
$return_to = Asset::find($licenseSeat->asset_id);
|
||||||
@@ -98,14 +98,17 @@ class LicenseCheckinController extends Controller
|
|||||||
$licenseSeat->notes = $request->input('notes');
|
$licenseSeat->notes = $request->input('notes');
|
||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
if ($request->get('redirect_option') === 'target'){
|
||||||
|
session()->put(['checkout_to_type' => 'user']);
|
||||||
|
}
|
||||||
|
|
||||||
// Was the asset updated?
|
// Was the asset updated?
|
||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
||||||
|
|
||||||
|
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkin.success'));
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
|
->with('success', trans('admin/licenses/message.checkin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the license page with error
|
// Redirect to the license page with error
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ class LicenseCheckoutController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if ($checkoutTarget) {
|
if ($checkoutTarget) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkout.success'));
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
|
->with('success', trans('admin/licenses/message.checkout.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ class LicensesController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($license->save()) {
|
if ($license->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.create.success'));
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
|
->with('success', trans('admin/licenses/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
||||||
@@ -125,7 +126,7 @@ class LicensesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('update', $license);
|
$this->authorize('update', $license);
|
||||||
|
session()->put('back_url', url()->previous());
|
||||||
$maintained_list = [
|
$maintained_list = [
|
||||||
'' => 'Maintained',
|
'' => 'Maintained',
|
||||||
'1' => 'Yes',
|
'1' => 'Yes',
|
||||||
@@ -181,7 +182,8 @@ class LicensesController extends Controller
|
|||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($license->save()) {
|
if ($license->save()) {
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.update.success'));
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
|
->with('success', trans('admin/licenses/message.update.success'));
|
||||||
}
|
}
|
||||||
// If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php
|
// If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php
|
||||||
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
||||||
|
|||||||
@@ -3,15 +3,21 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
use App\Http\Transformers\ProfileTransformer;
|
||||||
|
use App\Models\Actionlog;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\CurrentInventory;
|
use App\Notifications\CurrentInventory;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use \Illuminate\Contracts\View\View;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to User Profiles for
|
* This controller handles all actions related to User Profiles for
|
||||||
* the Snipe-IT Asset Management application.
|
* the Snipe-IT Asset Management application.
|
||||||
@@ -220,7 +226,7 @@ class ProfileController extends Controller
|
|||||||
|
|
||||||
if (!$user = User::find(auth()->id())) {
|
if (!$user = User::find(auth()->id())) {
|
||||||
return redirect()->back()
|
return redirect()->back()
|
||||||
->with('error', trans('admin/users/message.user_not_found', ['id' => $id]));
|
->with('error', trans('admin/users/message.user_not_found', ['id' => auth()->id()]));
|
||||||
}
|
}
|
||||||
if (empty($user->email)) {
|
if (empty($user->email)) {
|
||||||
return redirect()->back()->with('error', trans('admin/users/message.user_has_no_email'));
|
return redirect()->back()->with('error', trans('admin/users/message.user_has_no_email'));
|
||||||
@@ -234,4 +240,28 @@ class ProfileController extends Controller
|
|||||||
|
|
||||||
return redirect()->back()->with('success', trans('admin/users/general.user_notified'));
|
return redirect()->back()->with('success', trans('admin/users/general.user_notified'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
$logentry = Actionlog::where('filename', $filename)->first();
|
||||||
|
|
||||||
|
// Make sure the user has permission to view this file
|
||||||
|
if (auth()->id() != $logentry->target_id) {
|
||||||
|
return redirect()->route('account')->with('error', trans('general.generic_model_not_found', ['model' => 'file']));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(config('app.private_uploads').'/eula-pdfs/'.$filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ class ReportsController extends Controller
|
|||||||
$currency = e(Setting::getSettings()->default_currency);
|
$currency = e(Setting::getSettings()->default_currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
$row[] = $asset->purchase_date;
|
$row[] = Helper::getFormattedDateObject($asset->purchase_date, 'date', false);
|
||||||
$row[] = $currency.Helper::formatCurrencyOutput($asset->purchase_cost);
|
$row[] = $currency.Helper::formatCurrencyOutput($asset->purchase_cost);
|
||||||
$row[] = $currency.Helper::formatCurrencyOutput($asset->getDepreciatedValue());
|
$row[] = $currency.Helper::formatCurrencyOutput($asset->getDepreciatedValue());
|
||||||
$row[] = $currency.Helper::formatCurrencyOutput(($asset->purchase_cost - $asset->getDepreciatedValue()));
|
$row[] = $currency.Helper::formatCurrencyOutput(($asset->purchase_cost - $asset->getDepreciatedValue()));
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ class SettingsController extends Controller
|
|||||||
$setting->dash_chart_type = $request->input('dash_chart_type');
|
$setting->dash_chart_type = $request->input('dash_chart_type');
|
||||||
$setting->profile_edit = $request->input('profile_edit', 0);
|
$setting->profile_edit = $request->input('profile_edit', 0);
|
||||||
$setting->require_checkinout_notes = $request->input('require_checkinout_notes', 0);
|
$setting->require_checkinout_notes = $request->input('require_checkinout_notes', 0);
|
||||||
|
$setting->manager_view_enabled = $request->input('manager_view_enabled', 0);
|
||||||
|
|
||||||
|
|
||||||
if ($request->input('per_page') != '') {
|
if ($request->input('per_page') != '') {
|
||||||
@@ -650,6 +651,7 @@ class SettingsController extends Controller
|
|||||||
|
|
||||||
$setting->alert_email = $alert_email;
|
$setting->alert_email = $alert_email;
|
||||||
$setting->admin_cc_email = $admin_cc_email;
|
$setting->admin_cc_email = $admin_cc_email;
|
||||||
|
$setting->admin_cc_always = $request->validated('admin_cc_always');
|
||||||
$setting->alerts_enabled = $request->input('alerts_enabled', '0');
|
$setting->alerts_enabled = $request->input('alerts_enabled', '0');
|
||||||
$setting->alert_interval = $request->input('alert_interval');
|
$setting->alert_interval = $request->input('alert_interval');
|
||||||
$setting->alert_threshold = $request->input('alert_threshold');
|
$setting->alert_threshold = $request->input('alert_threshold');
|
||||||
@@ -922,7 +924,7 @@ class SettingsController extends Controller
|
|||||||
* @since v5.0.0
|
* @since v5.0.0
|
||||||
*/
|
*/
|
||||||
public function postSamlSettings(SettingsSamlRequest $request) : RedirectResponse
|
public function postSamlSettings(SettingsSamlRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($setting = Setting::getSettings())) {
|
if (is_null($setting = Setting::getSettings())) {
|
||||||
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
|
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ class UsersController extends Controller
|
|||||||
$user->notify(new WelcomeNotification($data));
|
$user->notify(new WelcomeNotification($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))->with('success', trans('admin/users/message.success.create'));
|
return Helper::getRedirectOption($request, $user->id, 'Users')
|
||||||
|
->with('success', trans('admin/users/message.success.create'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
||||||
@@ -178,7 +179,7 @@ class UsersController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param $permissions
|
* @param $permissions
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||||
* @internal param int $id
|
* @internal param int $id
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
@@ -186,10 +187,15 @@ class UsersController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('update', User::class);
|
$this->authorize('update', User::class);
|
||||||
|
session()->put('back_url', url()->previous());
|
||||||
$user = User::with(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed()->find($user->id);
|
$user = User::with(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed()->find($user->id);
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
|
||||||
|
if ($user->trashed()) {
|
||||||
|
return redirect()->route('users.show', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
$permissions = config('permissions');
|
$permissions = config('permissions');
|
||||||
$groups = Group::pluck('name', 'id');
|
$groups = Group::pluck('name', 'id');
|
||||||
|
|
||||||
@@ -308,7 +314,7 @@ class UsersController extends Controller
|
|||||||
|
|
||||||
if ($user->save()) {
|
if ($user->save()) {
|
||||||
// Redirect to the user page
|
// Redirect to the user page
|
||||||
return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))
|
return Helper::getRedirectOption($request, $user->id, 'Users')
|
||||||
->with('success', trans('admin/users/message.success.update'));
|
->with('success', trans('admin/users/message.success.update'));
|
||||||
}
|
}
|
||||||
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
||||||
@@ -506,6 +512,8 @@ class UsersController extends Controller
|
|||||||
trans('admin/companies/table.title'),
|
trans('admin/companies/table.title'),
|
||||||
trans('admin/users/table.title'),
|
trans('admin/users/table.title'),
|
||||||
trans('general.employee_number'),
|
trans('general.employee_number'),
|
||||||
|
trans('admin/users/table.first_name'),
|
||||||
|
trans('admin/users/table.last_name'),
|
||||||
trans('admin/users/table.name'),
|
trans('admin/users/table.name'),
|
||||||
trans('admin/users/table.username'),
|
trans('admin/users/table.username'),
|
||||||
trans('admin/users/table.email'),
|
trans('admin/users/table.email'),
|
||||||
@@ -551,6 +559,8 @@ class UsersController extends Controller
|
|||||||
($user->company) ? $user->company->name : '',
|
($user->company) ? $user->company->name : '',
|
||||||
$user->jobtitle,
|
$user->jobtitle,
|
||||||
$user->employee_num,
|
$user->employee_num,
|
||||||
|
$user->first_name,
|
||||||
|
$user->last_name,
|
||||||
$user->present()->fullName(),
|
$user->present()->fullName(),
|
||||||
$user->username,
|
$user->username,
|
||||||
$user->email,
|
$user->email,
|
||||||
|
|||||||
@@ -27,50 +27,126 @@ use Exception;
|
|||||||
class ViewAssetsController extends Controller
|
class ViewAssetsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Redirect to the profile page.
|
* Extract custom fields that should be displayed in user view.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function extractCustomFields(User $user): array
|
||||||
|
{
|
||||||
|
$fieldArray = [];
|
||||||
|
foreach ($user->assets as $asset) {
|
||||||
|
if ($asset->model && $asset->model->fieldset) {
|
||||||
|
foreach ($asset->model->fieldset->fields as $field) {
|
||||||
|
if ($field->display_in_user_view == '1') {
|
||||||
|
$fieldArray[$field->db_column] = $field->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array_unique($fieldArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of users viewable by the current user.
|
||||||
|
*
|
||||||
|
* @param User $authUser
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
private function getViewableUsers(User $authUser): \Illuminate\Support\Collection
|
||||||
|
{
|
||||||
|
// SuperAdmin sees all users
|
||||||
|
if ($authUser->isSuperUser()) {
|
||||||
|
return User::select('id', 'first_name', 'last_name', 'username')
|
||||||
|
->where('activated', 1)
|
||||||
|
->orderBy('last_name')
|
||||||
|
->orderBy('first_name')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular manager sees only their subordinates + self
|
||||||
|
$managedUsers = $authUser->getAllSubordinates();
|
||||||
|
|
||||||
|
// If user has subordinates, show them with self at beginning
|
||||||
|
if ($managedUsers->count() > 0) {
|
||||||
|
return collect([$authUser])->merge($managedUsers)
|
||||||
|
->sortBy('last_name')
|
||||||
|
->sortBy('first_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
// User has no subordinates, only sees themselves
|
||||||
|
return collect([$authUser]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected user ID from request or default to current user.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param \Illuminate\Support\Collection $subordinates
|
||||||
|
* @param int $defaultUserId
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getSelectedUserId(Request $request, \Illuminate\Support\Collection $subordinates, int $defaultUserId): int
|
||||||
|
{
|
||||||
|
// If no subordinates or no user_id in request, return default
|
||||||
|
if ($subordinates->count() <= 1 || !$request->filled('user_id')) {
|
||||||
|
return $defaultUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestedUserId = (int) $request->input('user_id');
|
||||||
|
|
||||||
|
// Validate if the requested user is allowed
|
||||||
|
if ($subordinates->contains('id', $requestedUserId)) {
|
||||||
|
return $requestedUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If invalid ID or not authorized, return default
|
||||||
|
return $defaultUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show user's assigned assets with optional manager view functionality.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getIndex() : View | RedirectResponse
|
public function getIndex(Request $request) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$user = User::with(
|
$authUser = auth()->user();
|
||||||
|
$settings = Setting::getSettings();
|
||||||
|
$subordinates = collect();
|
||||||
|
$selectedUserId = $authUser->id;
|
||||||
|
|
||||||
|
// Process manager view if enabled
|
||||||
|
if ($settings->manager_view_enabled) {
|
||||||
|
$subordinates = $this->getViewableUsers($authUser);
|
||||||
|
$selectedUserId = $this->getSelectedUserId($request, $subordinates, $authUser->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the data for the user to be viewed (either auth user or selected subordinate)
|
||||||
|
$userToView = User::with([
|
||||||
'assets',
|
'assets',
|
||||||
'assets.model',
|
'assets.model',
|
||||||
'assets.model.fieldset.fields',
|
'assets.model.fieldset.fields',
|
||||||
'consumables',
|
'consumables',
|
||||||
'accessories',
|
'accessories',
|
||||||
'licenses',
|
'licenses'
|
||||||
)->find(auth()->id());
|
])->find($selectedUserId);
|
||||||
|
|
||||||
$field_array = array();
|
|
||||||
|
|
||||||
// Loop through all the custom fields that are applied to any model the user has assigned
|
|
||||||
foreach ($user->assets as $asset) {
|
|
||||||
|
|
||||||
// Make sure the model has a custom fieldset before trying to loop through the associated fields
|
|
||||||
if ($asset->model->fieldset) {
|
|
||||||
|
|
||||||
foreach ($asset->model->fieldset->fields as $field) {
|
|
||||||
// check and make sure they're allowed to see the value of the custom field
|
|
||||||
if ($field->display_in_user_view == '1') {
|
|
||||||
$field_array[$field->db_column] = $field->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If the user to view couldn't be found (shouldn't happen with proper logic), redirect with error
|
||||||
|
if (!$userToView) {
|
||||||
|
return redirect()->route('view-assets')->with('error', trans('admin/users/message.user_not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since some models may re-use the same fieldsets/fields, let's make the array unique so we don't repeat columns
|
// Process custom fields for the user being viewed
|
||||||
array_unique($field_array);
|
$fieldArray = $this->extractCustomFields($userToView);
|
||||||
|
|
||||||
if (isset($user->id)) {
|
// Pass the necessary data to the view
|
||||||
return view('account/view-assets', compact('user', 'field_array' ))
|
return view('account/view-assets', [
|
||||||
->with('settings', Setting::getSettings());
|
'user' => $userToView, // Use 'user' for compatibility with the existing view
|
||||||
}
|
'field_array' => $fieldArray,
|
||||||
|
'settings' => $settings,
|
||||||
// Redirect to the user management page
|
'subordinates' => $subordinates,
|
||||||
return redirect()->route('users.index')
|
'selectedUserId' => $selectedUserId
|
||||||
->with('error', trans('admin/users/message.user_not_found', $user->id));
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class Kernel extends HttpKernel
|
|||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'api-throttle' => \App\Http\Middleware\SetAPIResponseHeaders::class,
|
||||||
'health' => null,
|
'health' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
82
app/Http/Middleware/SetAPIResponseHeaders.php
Normal file
82
app/Http/Middleware/SetAPIResponseHeaders.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class SetAPIResponseHeaders extends ThrottleRequests
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the rate limit headers to the response.
|
||||||
|
*
|
||||||
|
* This extends the original ThrottleRequests middleware to add the 'X-RateLimit-Reset' and 'Retry-After' headers, even
|
||||||
|
* if the rate limit is not exceeded.
|
||||||
|
* @param $maxAttempts
|
||||||
|
* @param $remainingAttempts
|
||||||
|
* @param $retryAfter
|
||||||
|
* @param Response|null $response
|
||||||
|
* @return array|int[]
|
||||||
|
*/
|
||||||
|
protected function getHeaders($maxAttempts, $remainingAttempts, $retryAfter = null, ?Response $response = null)
|
||||||
|
{
|
||||||
|
if ($response &&
|
||||||
|
! is_null($response->headers->get('X-RateLimit-Remaining')) &&
|
||||||
|
(int) $response->headers->get('X-RateLimit-Remaining') <= (int) $remainingAttempts) {
|
||||||
|
$headers = [];
|
||||||
|
$headers['Retry-After'] = $retryAfter; // this is the only line we changed
|
||||||
|
$headers['X-RateLimit-Reset'] = $retryAfter; // this is the only line we changed
|
||||||
|
$headers['X-RateLimit-Reset-Timestamp'] = $this->availableAt($retryAfter); // this is the only line we changed
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'X-RateLimit-Limit' => $maxAttempts,
|
||||||
|
'X-RateLimit-Remaining' => $remainingAttempts,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (! is_null($retryAfter)) {
|
||||||
|
$headers['Retry-After'] = $retryAfter;
|
||||||
|
$headers['X-RateLimit-Reset'] = $retryAfter; // this is the only line we changed
|
||||||
|
$headers['X-RateLimit-Reset-Timestamp'] = $this->availableAt($retryAfter); // this is the only line we changed
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function handleRequest($request, Closure $next, array $limits)
|
||||||
|
{
|
||||||
|
foreach ($limits as $limit) {
|
||||||
|
if ($this->limiter->tooManyAttempts($limit->key, $limit->maxAttempts)) {
|
||||||
|
throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->limiter->hit($limit->key, $limit->decaySeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
foreach ($limits as $limit) {
|
||||||
|
$response = $this->addHeaders(
|
||||||
|
$response,
|
||||||
|
$limit->maxAttempts,
|
||||||
|
$this->calculateRemainingAttempts($limit->key, $limit->maxAttempts),
|
||||||
|
$this->getTimeUntilNextRetry($limit->key) // this is the only line we changed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ class SettingsSamlRequest extends FormRequest
|
|||||||
public function withValidator($validator)
|
public function withValidator($validator)
|
||||||
{
|
{
|
||||||
$validator->after(function ($validator) {
|
$validator->after(function ($validator) {
|
||||||
|
$setting = Setting::getSettings();
|
||||||
if ($this->input('saml_enabled') == '1') {
|
if ($this->input('saml_enabled') == '1') {
|
||||||
$idpMetadata = $this->input('saml_idp_metadata');
|
$idpMetadata = $this->input('saml_idp_metadata');
|
||||||
if (! empty($idpMetadata)) {
|
if (! empty($idpMetadata)) {
|
||||||
@@ -56,7 +57,7 @@ class SettingsSamlRequest extends FormRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$was_custom_x509cert = strpos(Setting::getSettings()->saml_custom_settings, 'sp_x509cert') !== false;
|
$was_custom_x509cert = strpos($setting->saml_custom_settings, 'sp_x509cert') !== false;
|
||||||
|
|
||||||
$custom_x509cert = '';
|
$custom_x509cert = '';
|
||||||
$custom_privateKey = '';
|
$custom_privateKey = '';
|
||||||
@@ -126,10 +127,14 @@ class SettingsSamlRequest extends FormRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! (empty($x509cert) && empty($privateKey))) {
|
if (! (empty($x509cert) && empty($privateKey))) {
|
||||||
$this->merge([
|
// $this->merge([
|
||||||
'saml_sp_x509cert' => $x509cert,
|
// 'saml_sp_x509cert' => $x509cert,
|
||||||
'saml_sp_privatekey' => $privateKey,
|
// 'saml_sp_privatekey' => $privateKey,
|
||||||
]);
|
// ]);
|
||||||
|
$setting->saml_sp_x509cert = $x509cert;
|
||||||
|
$setting->saml_sp_privatekey = $privateKey;
|
||||||
|
$setting->save();
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$validator->errors()->add('saml_integration', 'openssl.cnf is missing/invalid');
|
$validator->errors()->add('saml_integration', 'openssl.cnf is missing/invalid');
|
||||||
@@ -145,15 +150,21 @@ class SettingsSamlRequest extends FormRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($x509certNew)) {
|
if (! empty($x509certNew)) {
|
||||||
$this->merge([
|
// $this->merge([
|
||||||
'saml_sp_x509certNew' => $x509certNew,
|
// 'saml_sp_x509certNew' => $x509certNew,
|
||||||
]);
|
// ]);
|
||||||
|
$setting->saml_sp_x509certNew = $x509certNew;
|
||||||
|
$setting->save();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->merge([
|
// $this->merge([
|
||||||
'saml_sp_x509certNew' => '',
|
// 'saml_sp_x509certNew' => '',
|
||||||
]);
|
// ]);
|
||||||
|
$setting->saml_sp_x509certNew = '';
|
||||||
|
$setting->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ class StoreLabelSettings extends FormRequest
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'labels_per_page' => 'numeric',
|
'labels_per_page' => 'numeric',
|
||||||
'labels_width' => 'numeric',
|
'labels_width' => 'numeric|min:0.1',
|
||||||
'labels_height' => 'numeric',
|
'labels_height' => 'numeric|min:0.1',
|
||||||
'labels_pmargin_left' => 'numeric|nullable',
|
'labels_pmargin_left' => 'numeric|nullable',
|
||||||
'labels_pmargin_right' => 'numeric|nullable',
|
'labels_pmargin_right' => 'numeric|nullable',
|
||||||
'labels_pmargin_top' => 'numeric|nullable',
|
'labels_pmargin_top' => 'numeric|nullable',
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Requests;
|
|||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class StoreNotificationSettings extends FormRequest
|
class StoreNotificationSettings extends FormRequest
|
||||||
{
|
{
|
||||||
@@ -26,6 +27,9 @@ class StoreNotificationSettings extends FormRequest
|
|||||||
return [
|
return [
|
||||||
'alert_email' => 'email_array|nullable',
|
'alert_email' => 'email_array|nullable',
|
||||||
'admin_cc_email' => 'email_array|nullable',
|
'admin_cc_email' => 'email_array|nullable',
|
||||||
|
'admin_cc_always' => [
|
||||||
|
Rule::in('0', '1'),
|
||||||
|
],
|
||||||
'alert_threshold' => 'numeric|nullable',
|
'alert_threshold' => 'numeric|nullable',
|
||||||
'alert_interval' => 'numeric|nullable|gt:0',
|
'alert_interval' => 'numeric|nullable|gt:0',
|
||||||
'audit_warning_days' => 'numeric|nullable',
|
'audit_warning_days' => 'numeric|nullable',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Http\Traits\ConvertsBase64ToFiles;
|
|||||||
use enshrined\svgSanitize\Sanitizer;
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use \App\Helpers\Helper;
|
||||||
|
|
||||||
class UploadFileRequest extends Request
|
class UploadFileRequest extends Request
|
||||||
{
|
{
|
||||||
@@ -27,44 +28,65 @@ class UploadFileRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
|
$max_file_size = Helper::file_upload_max_size();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp,avif|max:'.$max_file_size,
|
'file.*' => 'required|mimes:'.config('filesystems.allowed_upload_extensions_for_validator').'|max:'.$max_file_size,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes (if needed) and Saves a file to the appropriate location
|
* Sanitizes (if needed) and Saves a file to the appropriate location
|
||||||
* Returns the 'short' (storage-relative) filename
|
* Returns the 'short' (storage-relative) filename
|
||||||
*
|
|
||||||
* TODO - this has a lot of similarities to UploadImageRequest's handleImage; is there
|
|
||||||
* a way to merge them or extend one into the other?
|
|
||||||
*/
|
*/
|
||||||
public function handleFile(string $dirname, string $name_prefix, $file): string
|
public function handleFile(string $dirname, string $name_prefix, $file): string
|
||||||
{
|
{
|
||||||
|
|
||||||
$extension = $file->getClientOriginalExtension();
|
$extension = $file->getClientOriginalExtension();
|
||||||
$file_name = $name_prefix.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$file->guessExtension();
|
$file_name = $name_prefix.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$file->guessExtension();
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
// Check for SVG and sanitize it
|
||||||
if ($file->getMimeType() === 'image/svg+xml') {
|
if ($file->getMimeType() === 'image/svg+xml') {
|
||||||
Log::debug('This is an SVG');
|
$uploaded_file = $this->handleSVG($file);
|
||||||
Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put($dirname.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::debug('Upload no workie :( ');
|
|
||||||
Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$put_results = Storage::put($dirname.$file_name, file_get_contents($file));
|
$uploaded_file = file_get_contents($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Storage::put($dirname.$file_name, $uploaded_file);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::debug($e);
|
||||||
|
}
|
||||||
|
|
||||||
return $file_name;
|
return $file_name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function handleSVG($file)
|
||||||
|
{
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$dirtySVG = file_get_contents($file->getRealPath());
|
||||||
|
return $sanitizer->sanitize($dirtySVG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation error messages that apply to the request, but
|
||||||
|
* replace the attribute name with the name of the file that was attempted and failed
|
||||||
|
* to make it clearer to the user which file is the bad one.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
$attributes = [];
|
||||||
|
|
||||||
|
if ($this->file) {
|
||||||
|
for ($i = 0; $i < count($this->file); $i++) {
|
||||||
|
$attributes['file.'.$i] = $this->file[$i]->getClientOriginalName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -113,8 +113,8 @@ class ActionlogsTransformer
|
|||||||
|
|
||||||
// Display the changes if the user is an admin or superadmin
|
// Display the changes if the user is an admin or superadmin
|
||||||
if (Gate::allows('admin')) {
|
if (Gate::allows('admin')) {
|
||||||
$clean_meta[$fieldname]['old'] = ($enc_old) ? unserialize($enc_old): '';
|
$clean_meta[$fieldname]['old'] = ($enc_old) ? unserialize($enc_old, ['allowed_classes' => false]) : '';
|
||||||
$clean_meta[$fieldname]['new'] = ($enc_new) ? unserialize($enc_new): '';
|
$clean_meta[$fieldname]['new'] = ($enc_new) ? unserialize($enc_new, ['allowed_classes' => false]) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -198,8 +198,8 @@ class ActionlogsTransformer
|
|||||||
'note' => ($actionlog->note) ? Helper::parseEscapedMarkedownInline($actionlog->note): null,
|
'note' => ($actionlog->note) ? Helper::parseEscapedMarkedownInline($actionlog->note): null,
|
||||||
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
|
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
|
||||||
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
|
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
|
||||||
'remote_ip' => ($actionlog->remote_ip) ?? null,
|
'remote_ip' => e($actionlog->remote_ip) ?? null,
|
||||||
'user_agent' => ($actionlog->user_agent) ?? null,
|
'user_agent' => e($actionlog->user_agent) ?? null,
|
||||||
'action_source' => ($actionlog->action_source) ?? null,
|
'action_source' => ($actionlog->action_source) ?? null,
|
||||||
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -59,7 +59,10 @@ class AssetMaintenancesTransformer
|
|||||||
'name'=> e($assetmaintenance->asset->defaultLoc->name),
|
'name'=> e($assetmaintenance->asset->defaultLoc->name),
|
||||||
] : null,
|
] : null,
|
||||||
'notes' => ($assetmaintenance->notes) ? Helper::parseEscapedMarkedownInline($assetmaintenance->notes) : null,
|
'notes' => ($assetmaintenance->notes) ? Helper::parseEscapedMarkedownInline($assetmaintenance->notes) : null,
|
||||||
'supplier' => ($assetmaintenance->supplier) ? ['id' => $assetmaintenance->supplier->id, 'name'=> e($assetmaintenance->supplier->name)] : null,
|
'supplier' => ($assetmaintenance->supplier) ? [
|
||||||
|
'id' => $assetmaintenance->supplier->id,
|
||||||
|
'name'=> e($assetmaintenance->supplier->name)
|
||||||
|
] : null,
|
||||||
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
|
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
|
||||||
'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type),
|
'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type),
|
||||||
'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'),
|
'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'),
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ class AssetsTransformer
|
|||||||
'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null,
|
'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null,
|
||||||
'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null,
|
'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null,
|
||||||
'assigned_to' => $this->transformAssignedTo($asset),
|
'assigned_to' => $this->transformAssignedTo($asset),
|
||||||
|
'jobtitle' => $asset->assigned ? e($asset->assigned->jobtitle) : null,
|
||||||
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
|
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
|
||||||
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
|
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
|
||||||
'created_by' => ($asset->adminuser) ? [
|
'created_by' => ($asset->adminuser) ? [
|
||||||
@@ -101,7 +102,7 @@ class AssetsTransformer
|
|||||||
'checkout_counter' => (int) $asset->checkout_counter,
|
'checkout_counter' => (int) $asset->checkout_counter,
|
||||||
'requests_counter' => (int) $asset->requests_counter,
|
'requests_counter' => (int) $asset->requests_counter,
|
||||||
'user_can_checkout' => (bool) $asset->availableForCheckout(),
|
'user_can_checkout' => (bool) $asset->availableForCheckout(),
|
||||||
'book_value' => Helper::formatCurrencyOutput($asset->getLinearDepreciatedValue()),
|
'book_value' => Helper::formatCurrencyOutput($asset->getDepreciatedValue()),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ namespace App\Http\Transformers;
|
|||||||
|
|
||||||
class DatatablesTransformer
|
class DatatablesTransformer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform data for bootstrap tables and API responses for lists of things
|
||||||
|
**/
|
||||||
public function transformDatatables($objects, $total = null)
|
public function transformDatatables($objects, $total = null)
|
||||||
{
|
{
|
||||||
(isset($total)) ? $objects_array['total'] = $total : $objects_array['total'] = count($objects);
|
(isset($total)) ? $objects_array['total'] = $total : $objects_array['total'] = count($objects);
|
||||||
@@ -11,4 +15,15 @@ class DatatablesTransformer
|
|||||||
|
|
||||||
return $objects_array;
|
return $objects_array;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Transform data for returning the status of items within a bulk action
|
||||||
|
**/
|
||||||
|
public function transformBulkResponseWithStatusAndObjects($objects, $total)
|
||||||
|
{
|
||||||
|
(isset($total)) ? $objects_array['total'] = $total : $objects_array['total'] = count($objects);
|
||||||
|
$objects_array['rows'] = $objects;
|
||||||
|
|
||||||
|
return $objects_array;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,11 +26,11 @@ class DepreciationsTransformer
|
|||||||
$array = [
|
$array = [
|
||||||
'id' => (int) $depreciation->id,
|
'id' => (int) $depreciation->id,
|
||||||
'name' => e($depreciation->name),
|
'name' => e($depreciation->name),
|
||||||
'months' => $depreciation->months.' '.trans('general.months'),
|
'months' => trans_choice('general.months_plural', $depreciation->months),
|
||||||
'depreciation_min' => $depreciation->depreciation_type === 'percent' ? $depreciation->depreciation_min.'%' : $depreciation->depreciation_min,
|
'depreciation_min' => $depreciation->depreciation_type === 'percent' ? $depreciation->depreciation_min.'%' : $depreciation->depreciation_min,
|
||||||
'assets_count' => $depreciation->assets_count,
|
'assets_count' => ($depreciation->assets_count > 0) ? (int) $depreciation->assets_count : 0,
|
||||||
'models_count' => $depreciation->models_count,
|
'models_count' => ($depreciation->models_count > 0) ? (int) $depreciation->models_count : 0,
|
||||||
'licenses_count' => $depreciation->licenses_count,
|
'licenses_count' => ($depreciation->licenses_count > 0) ? (int) $depreciation->licenses_count : 0,
|
||||||
'created_by' => ($depreciation->adminuser) ? [
|
'created_by' => ($depreciation->adminuser) ? [
|
||||||
'id' => (int) $depreciation->adminuser->id,
|
'id' => (int) $depreciation->adminuser->id,
|
||||||
'name'=> e($depreciation->adminuser->present()->fullName()),
|
'name'=> e($depreciation->adminuser->present()->fullName()),
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ class LocationsTransformer
|
|||||||
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
||||||
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
||||||
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
|
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
|
||||||
|
'created_by' => $location->adminuser ? [
|
||||||
|
'id' => (int) $location->adminuser->id,
|
||||||
|
'name'=> e($location->adminuser->present()->fullName),
|
||||||
|
]: null,
|
||||||
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
|
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
|
||||||
'parent' => ($location->parent) ? [
|
'parent' => ($location->parent) ? [
|
||||||
'id' => (int) $location->parent->id,
|
'id' => (int) $location->parent->id,
|
||||||
|
|||||||
43
app/Http/Transformers/ProfileTransformer.php
Normal file
43
app/Http/Transformers/ProfileTransformer.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Transformers;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use App\Models\Asset;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
|
class ProfileTransformer
|
||||||
|
{
|
||||||
|
public function transformFiles(Collection $files, $total)
|
||||||
|
{
|
||||||
|
$array = [];
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$array[] = self::transformFile($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function transformFile(Actionlog $file)
|
||||||
|
{
|
||||||
|
$array = [
|
||||||
|
'id' => (int) $file->id,
|
||||||
|
'icon' => Helper::filetype_icon($file->filename),
|
||||||
|
'item' => ($file->item) ? [
|
||||||
|
'name' => ($file->itemType()=='user') ? e($file->item->getFullNameAttribute()) : e($file->item->getDisplayNameAttribute()),
|
||||||
|
'type' => e($file->itemType()),
|
||||||
|
] : null,
|
||||||
|
'filename' => e($file->filename),
|
||||||
|
'signature_file' => ($file->accept_signature) ? route('profile.signature.view', ['filename' => $file->accept_signature ]) : null,
|
||||||
|
'note' => e($file->note),
|
||||||
|
'url' => route('profile.storedeula.download', ['filename' => $file->filename]),
|
||||||
|
'file' => route('profile.storedeula.download', ['filename' => $file->filename]),
|
||||||
|
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -45,6 +45,10 @@ class SuppliersTransformer
|
|||||||
'components_count' => (int) $supplier->components_count,
|
'components_count' => (int) $supplier->components_count,
|
||||||
'notes' => ($supplier->notes) ? Helper::parseEscapedMarkedownInline($supplier->notes) : null,
|
'notes' => ($supplier->notes) ? Helper::parseEscapedMarkedownInline($supplier->notes) : null,
|
||||||
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
|
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
|
||||||
|
'created_by' => $supplier->adminuser ? [
|
||||||
|
'id' => (int) $supplier->adminuser->id,
|
||||||
|
'name'=> e($supplier->adminuser->present()->fullName),
|
||||||
|
]: null,
|
||||||
'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'),
|
'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
namespace App\Http\Transformers;
|
namespace App\Http\Transformers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Helpers\StorageHelper;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class UploadedFilesTransformer
|
class UploadedFilesTransformer
|
||||||
@@ -26,23 +26,26 @@ class UploadedFilesTransformer
|
|||||||
{
|
{
|
||||||
$snipeModel = $file->item_type;
|
$snipeModel = $file->item_type;
|
||||||
|
|
||||||
|
|
||||||
// This will be used later as we extend out this transformer to handle more types of uploads
|
|
||||||
if ($file->item_type == Asset::class) {
|
|
||||||
$file_url = route('show/assetfile', [$file->item_id, $file->id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$array = [
|
$array = [
|
||||||
'id' => (int) $file->id,
|
'id' => (int) $file->id,
|
||||||
|
'icon' => Helper::filetype_icon($file->filename),
|
||||||
|
'name' => e($file->filename),
|
||||||
|
'item' => ($file->item_type) ? [
|
||||||
|
'id' => (int) $file->item_id,
|
||||||
|
'type' => strtolower(class_basename($file->item_type)),
|
||||||
|
] : null,
|
||||||
'filename' => e($file->filename),
|
'filename' => e($file->filename),
|
||||||
'url' => $file_url,
|
'filetype' => StorageHelper::getFiletype($file->uploads_file_path()),
|
||||||
|
'url' => $file->uploads_file_url(),
|
||||||
|
'note' => ($file->note) ? e($file->note) : null,
|
||||||
'created_by' => ($file->adminuser) ? [
|
'created_by' => ($file->adminuser) ? [
|
||||||
'id' => (int) $file->adminuser->id,
|
'id' => (int) $file->adminuser->id,
|
||||||
'name'=> e($file->adminuser->present()->fullName),
|
'name'=> e($file->adminuser->present()->fullName),
|
||||||
] : null,
|
] : null,
|
||||||
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
|
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
|
||||||
'updated_at' => Helper::getFormattedDateObject($file->updated_at, 'datetime'),
|
|
||||||
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
|
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
|
||||||
|
'inline' => StorageHelper::allowSafeInline($file->uploads_file_path()),
|
||||||
|
'exists_on_disk' => (Storage::exists($file->uploads_file_path()) ? true : false),
|
||||||
];
|
];
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
@@ -53,4 +56,5 @@ class UploadedFilesTransformer
|
|||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
}
|
||||||
@@ -50,6 +50,10 @@ class UsersTransformer
|
|||||||
'id' => (int) $user->department->id,
|
'id' => (int) $user->department->id,
|
||||||
'name'=> e($user->department->name),
|
'name'=> e($user->department->name),
|
||||||
] : null,
|
] : null,
|
||||||
|
'department_manager' => ($user->department?->manager) ? [
|
||||||
|
'id' => (int) $user->department->manager->id,
|
||||||
|
'name'=> e($user->department->manager->full_name),
|
||||||
|
] : null,
|
||||||
'location' => ($user->userloc) ? [
|
'location' => ($user->userloc) ? [
|
||||||
'id' => (int) $user->userloc->id,
|
'id' => (int) $user->userloc->id,
|
||||||
'name'=> e($user->userloc->name),
|
'name'=> e($user->userloc->name),
|
||||||
|
|||||||
@@ -80,7 +80,16 @@ class AssetImporter extends ItemImporter
|
|||||||
$asset_tag = Asset::autoincrement_asset();
|
$asset_tag = Asset::autoincrement_asset();
|
||||||
}
|
}
|
||||||
|
|
||||||
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
|
||||||
|
|
||||||
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
|
// Override asset if an ID was given
|
||||||
|
\Log::debug('Finding asset by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
|
$asset = Asset::find($this->findCsvMatch($row, 'id'));
|
||||||
|
} else {
|
||||||
|
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
||||||
|
}
|
||||||
|
|
||||||
if ($asset) {
|
if ($asset) {
|
||||||
if (! $this->updating) {
|
if (! $this->updating) {
|
||||||
$exists_error = trans('general.import_asset_tag_exists', ['asset_tag' => $asset_tag]);
|
$exists_error = trans('general.import_asset_tag_exists', ['asset_tag' => $asset_tag]);
|
||||||
|
|||||||
99
app/Importer/CategoryImporter.php
Normal file
99
app/Importer/CategoryImporter.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Importer;
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
|
||||||
|
* Importer\Importer.php. [ALG]
|
||||||
|
*
|
||||||
|
* Class CategoryImporter
|
||||||
|
*/
|
||||||
|
class CategoryImporter extends ItemImporter
|
||||||
|
{
|
||||||
|
protected $categories;
|
||||||
|
|
||||||
|
public function __construct($filename)
|
||||||
|
{
|
||||||
|
parent::__construct($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handle($row)
|
||||||
|
{
|
||||||
|
parent::handle($row);
|
||||||
|
$this->createCategoryIfNotExists($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a category if a duplicate does not exist.
|
||||||
|
* @todo Investigate how this should interact with Importer::createCategoryIfNotExists
|
||||||
|
*
|
||||||
|
* @author A. Gianotto
|
||||||
|
* @since 6.1.0
|
||||||
|
* @param array $row
|
||||||
|
*/
|
||||||
|
public function createCategoryIfNotExists(array $row)
|
||||||
|
{
|
||||||
|
|
||||||
|
$editingCategory = false;
|
||||||
|
|
||||||
|
$category = Category::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||||
|
|
||||||
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
|
// Override category if an ID was given
|
||||||
|
\Log::debug('Finding category by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
|
$category = Category::find($this->findCsvMatch($row, 'id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($category) {
|
||||||
|
if (! $this->updating) {
|
||||||
|
$this->log('A matching Category '.$this->item['name'].' already exists');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->log('Updating Category');
|
||||||
|
$editingCategory = true;
|
||||||
|
} else {
|
||||||
|
$this->log('No Matching Category, Create a new one');
|
||||||
|
$category = new Category;
|
||||||
|
$category->created_by = auth()->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the records from the CSV to determine their values
|
||||||
|
$this->item['name'] = trim($this->findCsvMatch($row, 'name'));
|
||||||
|
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
|
||||||
|
$this->item['eula_text'] = trim($this->findCsvMatch($row, 'eula_text'));
|
||||||
|
$this->item['category_type'] = trim(strtolower($this->findCsvMatch($row, 'category_type')));
|
||||||
|
$this->item['use_default_eula'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'use_default_eula'))) == 1) ? 1 : 0;
|
||||||
|
$this->item['require_acceptance'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_acceptance'))) == 1) ? 1 : 0;
|
||||||
|
$this->item['checkin_email'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'checkin_email'))) == 1) ? 1 : 0;
|
||||||
|
|
||||||
|
|
||||||
|
Log::debug('Item array is: ');
|
||||||
|
Log::debug(print_r($this->item, true));
|
||||||
|
|
||||||
|
|
||||||
|
if ($editingCategory) {
|
||||||
|
Log::debug('Updating existing category');
|
||||||
|
$category->update($this->sanitizeItemForUpdating($category));
|
||||||
|
} else {
|
||||||
|
Log::debug('Creating category');
|
||||||
|
$category->fill($this->sanitizeItemForStoring($category));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($category->save()) {
|
||||||
|
$this->log('Category '.$category->name.' created or updated from CSV import');
|
||||||
|
return $category;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug($category->getErrors());
|
||||||
|
$this->logError($category, 'Category "'.$this->item['name'].'"');
|
||||||
|
return $category->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,6 +88,7 @@ abstract class Importer
|
|||||||
'department' => 'department',
|
'department' => 'department',
|
||||||
'manager_name' => 'manager full name',
|
'manager_name' => 'manager full name',
|
||||||
'manager_username' => 'manager username',
|
'manager_username' => 'manager username',
|
||||||
|
'manager_employee_num' => 'manager employee number',
|
||||||
'min_amt' => 'minimum quantity',
|
'min_amt' => 'minimum quantity',
|
||||||
'remote' => 'remote',
|
'remote' => 'remote',
|
||||||
'vip' => 'vip',
|
'vip' => 'vip',
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class ItemImporter extends Importer
|
|||||||
protected function determineCheckout($row)
|
protected function determineCheckout($row)
|
||||||
{
|
{
|
||||||
// Locations don't get checked out to anyone/anything
|
// Locations don't get checked out to anyone/anything
|
||||||
if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class)) {
|
if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class) || (get_class($this) == SupplierImporter::class) || (get_class($this) == ManufacturerImporter::class) || (get_class($this) == CategoryImporter::class)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,16 +353,27 @@ class ItemImporter extends Importer
|
|||||||
* @param $user_manager string
|
* @param $user_manager string
|
||||||
* @return int id of company created/found
|
* @return int id of company created/found
|
||||||
*/
|
*/
|
||||||
public function fetchManager($user_manager_first_name, $user_manager_last_name)
|
public function fetchManager($user_manager_username = null, $user_manager_employee_num = null, $user_manager_first_name = null, $user_manager_last_name = null)
|
||||||
{
|
{
|
||||||
$manager = User::where('first_name', '=', $user_manager_first_name)
|
if ($user_manager_username!='') {
|
||||||
->where('last_name', '=', $user_manager_last_name)->first();
|
$manager = User::where('username', '=', $user_manager_username)->first();
|
||||||
|
$this->log('Checking on username '.$user_manager_username);
|
||||||
|
} elseif ($user_manager_employee_num!='') {
|
||||||
|
$manager = User::where('employee_num', '=', $user_manager_employee_num)->first();
|
||||||
|
$this->log('Checking on employee_num '.$user_manager_employee_num);
|
||||||
|
} else {
|
||||||
|
$manager = User::where('first_name', '=', $user_manager_first_name)
|
||||||
|
->where('last_name', '=', $user_manager_last_name)->first();
|
||||||
|
$this->log('Checking on full name');
|
||||||
|
}
|
||||||
|
|
||||||
if ($manager) {
|
if ($manager) {
|
||||||
$this->log('A matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' already exists');
|
$this->log('A matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' already exists');
|
||||||
|
|
||||||
return $manager->id;
|
return $manager->id;
|
||||||
}
|
}
|
||||||
$this->log('No matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' found. If their user account is being created through this import, you should re-process this file again. ');
|
|
||||||
|
$this->log('No matching Manager found. If their user account is being created through this import, you should re-process this file again. ');
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
101
app/Importer/ManufacturerImporter.php
Normal file
101
app/Importer/ManufacturerImporter.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Importer;
|
||||||
|
|
||||||
|
use App\Models\Manufacturer;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
|
||||||
|
* Importer\Importer.php. [ALG]
|
||||||
|
*
|
||||||
|
* Class ManufacturerImporter
|
||||||
|
*/
|
||||||
|
class ManufacturerImporter extends ItemImporter
|
||||||
|
{
|
||||||
|
protected $manufacturers;
|
||||||
|
|
||||||
|
public function __construct($filename)
|
||||||
|
{
|
||||||
|
parent::__construct($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handle($row)
|
||||||
|
{
|
||||||
|
parent::handle($row);
|
||||||
|
$this->createManufacturerIfNotExists($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a supplier if a duplicate does not exist.
|
||||||
|
* @todo Investigate how this should interact with Importer::createManufacturerIfNotExists
|
||||||
|
*
|
||||||
|
* @author A. Gianotto
|
||||||
|
* @since 6.1.0
|
||||||
|
* @param array $row
|
||||||
|
*/
|
||||||
|
public function createManufacturerIfNotExists(array $row)
|
||||||
|
{
|
||||||
|
|
||||||
|
$editingManufacturer = false;
|
||||||
|
|
||||||
|
$supplier = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||||
|
|
||||||
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
|
// Override supplier if an ID was given
|
||||||
|
\Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
|
$supplier = Manufacturer::find($this->findCsvMatch($row, 'id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($supplier) {
|
||||||
|
if (! $this->updating) {
|
||||||
|
$this->log('A matching Manufacturer '.$this->item['name'].' already exists');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->log('Updating Manufacturer');
|
||||||
|
$editingManufacturer = true;
|
||||||
|
} else {
|
||||||
|
$this->log('No Matching Manufacturer, Create a new one');
|
||||||
|
$supplier = new Manufacturer;
|
||||||
|
$supplier->created_by = auth()->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the records from the CSV to determine their values
|
||||||
|
$this->item['name'] = trim($this->findCsvMatch($row, 'name'));
|
||||||
|
$this->item['support_phone'] = trim($this->findCsvMatch($row, 'support_phone'));
|
||||||
|
$this->item['fax'] = trim($this->findCsvMatch($row, 'fax'));
|
||||||
|
$this->item['support_email'] = trim($this->findCsvMatch($row, 'support_email'));
|
||||||
|
$this->item['contact'] = trim($this->findCsvMatch($row, 'contact'));
|
||||||
|
$this->item['url'] = trim($this->findCsvMatch($row, 'url'));
|
||||||
|
$this->item['support_url'] = trim($this->findCsvMatch($row, 'support_url'));
|
||||||
|
$this->item['warranty_lookup_url'] = trim($this->findCsvMatch($row, 'warranty_lookup_url'));
|
||||||
|
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
|
||||||
|
|
||||||
|
|
||||||
|
Log::debug('Item array is: ');
|
||||||
|
Log::debug(print_r($this->item, true));
|
||||||
|
|
||||||
|
|
||||||
|
if ($editingManufacturer) {
|
||||||
|
Log::debug('Updating existing supplier');
|
||||||
|
$supplier->update($this->sanitizeItemForUpdating($supplier));
|
||||||
|
} else {
|
||||||
|
Log::debug('Creating supplier');
|
||||||
|
$supplier->fill($this->sanitizeItemForStoring($supplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($supplier->save()) {
|
||||||
|
$this->log('Manufacturer '.$supplier->name.' created or updated from CSV import');
|
||||||
|
return $supplier;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug($supplier->getErrors());
|
||||||
|
$this->logError($supplier, 'Manufacturer "'.$this->item['name'].'"');
|
||||||
|
return $supplier->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
105
app/Importer/SupplierImporter.php
Normal file
105
app/Importer/SupplierImporter.php
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Importer;
|
||||||
|
|
||||||
|
use App\Models\Supplier;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
|
||||||
|
* Importer\Importer.php. [ALG]
|
||||||
|
*
|
||||||
|
* Class SupplierImporter
|
||||||
|
*/
|
||||||
|
class SupplierImporter extends ItemImporter
|
||||||
|
{
|
||||||
|
protected $suppliers;
|
||||||
|
|
||||||
|
public function __construct($filename)
|
||||||
|
{
|
||||||
|
parent::__construct($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handle($row)
|
||||||
|
{
|
||||||
|
parent::handle($row);
|
||||||
|
$this->createSupplierIfNotExists($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a supplier if a duplicate does not exist.
|
||||||
|
* @todo Investigate how this should interact with Importer::createSupplierIfNotExists
|
||||||
|
*
|
||||||
|
* @author A. Gianotto
|
||||||
|
* @since 6.1.0
|
||||||
|
* @param array $row
|
||||||
|
*/
|
||||||
|
public function createSupplierIfNotExists(array $row)
|
||||||
|
{
|
||||||
|
|
||||||
|
$editingSupplier = false;
|
||||||
|
|
||||||
|
$supplier = Supplier::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||||
|
|
||||||
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
|
// Override supplier if an ID was given
|
||||||
|
\Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
|
$supplier = Supplier::find($this->findCsvMatch($row, 'id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($supplier) {
|
||||||
|
if (! $this->updating) {
|
||||||
|
$this->log('A matching Supplier '.$this->item['name'].' already exists');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->log('Updating Supplier');
|
||||||
|
$editingSupplier = true;
|
||||||
|
} else {
|
||||||
|
$this->log('No Matching Supplier, Create a new one');
|
||||||
|
$supplier = new Supplier;
|
||||||
|
$supplier->created_by = auth()->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the records from the CSV to determine their values
|
||||||
|
$this->item['name'] = trim($this->findCsvMatch($row, 'name'));
|
||||||
|
$this->item['address'] = trim($this->findCsvMatch($row, 'address'));
|
||||||
|
$this->item['address2'] = trim($this->findCsvMatch($row, 'address2'));
|
||||||
|
$this->item['city'] = trim($this->findCsvMatch($row, 'city'));
|
||||||
|
$this->item['state'] = trim($this->findCsvMatch($row, 'state'));
|
||||||
|
$this->item['country'] = trim($this->findCsvMatch($row, 'country'));
|
||||||
|
$this->item['zip'] = trim($this->findCsvMatch($row, 'zip'));
|
||||||
|
$this->item['phone'] = trim($this->findCsvMatch($row, 'phone'));
|
||||||
|
$this->item['fax'] = trim($this->findCsvMatch($row, 'fax'));
|
||||||
|
$this->item['email'] = trim($this->findCsvMatch($row, 'email'));
|
||||||
|
$this->item['contact'] = trim($this->findCsvMatch($row, 'contact'));
|
||||||
|
$this->item['url'] = trim($this->findCsvMatch($row, 'url'));
|
||||||
|
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
|
||||||
|
|
||||||
|
|
||||||
|
Log::debug('Item array is: ');
|
||||||
|
Log::debug(print_r($this->item, true));
|
||||||
|
|
||||||
|
|
||||||
|
if ($editingSupplier) {
|
||||||
|
Log::debug('Updating existing supplier');
|
||||||
|
$supplier->update($this->sanitizeItemForUpdating($supplier));
|
||||||
|
} else {
|
||||||
|
Log::debug('Creating supplier');
|
||||||
|
$supplier->fill($this->sanitizeItemForStoring($supplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($supplier->save()) {
|
||||||
|
$this->log('Supplier '.$supplier->name.' created or updated from CSV import');
|
||||||
|
return $supplier;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug($supplier->getErrors());
|
||||||
|
$this->logError($supplier, 'Supplier "'.$this->item['name'].'"');
|
||||||
|
return $supplier->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ class UserImporter extends ItemImporter
|
|||||||
$this->item['activated'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'activated'))) == 1) ? '1' : 0;
|
$this->item['activated'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'activated'))) == 1) ? '1' : 0;
|
||||||
$this->item['employee_num'] = trim($this->findCsvMatch($row, 'employee_num'));
|
$this->item['employee_num'] = trim($this->findCsvMatch($row, 'employee_num'));
|
||||||
$this->item['department_id'] = trim($this->createOrFetchDepartment(trim($this->findCsvMatch($row, 'department'))));
|
$this->item['department_id'] = trim($this->createOrFetchDepartment(trim($this->findCsvMatch($row, 'department'))));
|
||||||
$this->item['manager_id'] = $this->fetchManager(trim($this->findCsvMatch($row, 'manager_first_name')), trim($this->findCsvMatch($row, 'manager_last_name')));
|
$this->item['manager_id'] = $this->fetchManager(trim($this->findCsvMatch($row, 'manager_username')), trim($this->findCsvMatch($row, 'manager_employee_num')), trim($this->findCsvMatch($row, 'manager_first_name')), trim($this->findCsvMatch($row, 'manager_last_name')));
|
||||||
$this->item['remote'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'remote'))) == 1 ) ? '1' : 0;
|
$this->item['remote'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'remote'))) == 1 ) ? '1' : 0;
|
||||||
$this->item['vip'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'vip'))) ==1 ) ? '1' : 0;
|
$this->item['vip'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'vip'))) ==1 ) ? '1' : 0;
|
||||||
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'autoassign_licenses'))) ==1 ) ? '1' : 0;
|
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'autoassign_licenses'))) ==1 ) ? '1' : 0;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use App\Mail\CheckoutConsumableMail;
|
|||||||
use App\Mail\CheckoutLicenseMail;
|
use App\Mail\CheckoutLicenseMail;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
|
use App\Models\Category;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
@@ -27,6 +28,7 @@ use App\Notifications\CheckoutAssetNotification;
|
|||||||
use App\Notifications\CheckoutConsumableNotification;
|
use App\Notifications\CheckoutConsumableNotification;
|
||||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||||
use GuzzleHttp\Exception\ClientException;
|
use GuzzleHttp\Exception\ClientException;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Exception;
|
use Exception;
|
||||||
@@ -40,6 +42,24 @@ class CheckoutableListener
|
|||||||
Component::class,
|
Component::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the listeners for the subscriber.
|
||||||
|
*
|
||||||
|
* @param Illuminate\Events\Dispatcher $events
|
||||||
|
*/
|
||||||
|
public function subscribe($events)
|
||||||
|
{
|
||||||
|
$events->listen(
|
||||||
|
\App\Events\CheckoutableCheckedIn::class,
|
||||||
|
'App\Listeners\CheckoutableListener@onCheckedIn'
|
||||||
|
);
|
||||||
|
|
||||||
|
$events->listen(
|
||||||
|
\App\Events\CheckoutableCheckedOut::class,
|
||||||
|
'App\Listeners\CheckoutableListener@onCheckedOut'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the user and post to webhook about the checked out checkoutable
|
* Notify the user and post to webhook about the checked out checkoutable
|
||||||
* and add a record to the checkout_requests table.
|
* and add a record to the checkout_requests table.
|
||||||
@@ -50,93 +70,70 @@ class CheckoutableListener
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a checkout acceptance and attach it in the notification
|
|
||||||
*/
|
|
||||||
$settings = Setting::getSettings();
|
|
||||||
$acceptance = $this->getCheckoutAcceptance($event);
|
$acceptance = $this->getCheckoutAcceptance($event);
|
||||||
$adminCcEmailsArray = [];
|
|
||||||
|
|
||||||
if ($settings->admin_cc_email !== '') {
|
$shouldSendEmailToUser = $this->shouldSendCheckoutEmailToUser($event->checkoutable);
|
||||||
$adminCcEmail = $settings->admin_cc_email;
|
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress($acceptance);
|
||||||
$adminCcEmailsArray = array_map('trim', explode(',', $adminCcEmail));
|
$shouldSendWebhookNotification = $this->shouldSendWebhookNotification();
|
||||||
|
|
||||||
|
if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress && !$shouldSendWebhookNotification) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
$ccEmails = array_filter($adminCcEmailsArray);
|
|
||||||
$mailable = $this->getCheckoutMailType($event, $acceptance);
|
|
||||||
$notifiable = $this->getNotifiableUsers($event);
|
|
||||||
|
|
||||||
|
if ($shouldSendEmailToUser || $shouldSendEmailToAlertAddress) {
|
||||||
|
$mailable = $this->getCheckoutMailType($event, $acceptance);
|
||||||
|
$notifiable = $this->getNotifiableUser($event);
|
||||||
|
|
||||||
// Send email notifications
|
$notifiableHasEmail = $notifiable instanceof User && $notifiable->email;
|
||||||
try {
|
|
||||||
/**
|
|
||||||
* Send an email if any of the following conditions are met:
|
|
||||||
* 1. The asset requires acceptance
|
|
||||||
* 2. The item has a EULA
|
|
||||||
* 3. The item should send an email at check-in/check-out
|
|
||||||
* 4. If the admin CC email is set, even if the item being checked out doesn't have an email address (location, etc)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ($event->checkoutable->requireAcceptance() || $event->checkoutable->getEula() ||
|
$shouldSendEmailToUser = $shouldSendEmailToUser && $notifiableHasEmail;
|
||||||
$this->checkoutableShouldSendEmail($event)) {
|
|
||||||
|
|
||||||
|
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
|
||||||
|
|
||||||
// Send a checkout email to the admin CC addresses, even if the target has no email
|
if (!empty($to)) {
|
||||||
if (!empty($ccEmails)) {
|
try {
|
||||||
Mail::to($ccEmails)->send($mailable);
|
Mail::to(array_flatten($to))->cc(array_flatten($cc))->send($mailable);
|
||||||
Log::info('Checkout Mail sent to CC addresses');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a checkout email to the target if it has an email
|
|
||||||
if (!empty($notifiable->email)) {
|
|
||||||
Mail::to($notifiable)->send($mailable);
|
|
||||||
Log::info('Checkout Mail sent to checkout target');
|
Log::info('Checkout Mail sent to checkout target');
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} 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 notification
|
if ($shouldSendWebhookNotification) {
|
||||||
try {
|
try {
|
||||||
if ($this->shouldSendWebhookNotification()) {
|
|
||||||
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
||||||
$message = $this->getCheckoutNotification($event)->toMicrosoftTeams();
|
$message = $this->getCheckoutNotification($event)->toMicrosoftTeams();
|
||||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||||
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||||
->notify($this->getCheckoutNotification($event, $acceptance));
|
->notify($this->getCheckoutNotification($event, $acceptance));
|
||||||
}
|
}
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
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(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'));
|
||||||
}
|
}
|
||||||
} catch (ClientException $e) {
|
|
||||||
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(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
|
* Notify the user and post to webhook about the checked in checkoutable
|
||||||
*/
|
*/
|
||||||
public function onCheckedIn($event)
|
public function onCheckedIn($event)
|
||||||
{
|
{
|
||||||
Log::debug('onCheckedIn in the Checkoutable listener fired');
|
Log::debug('onCheckedIn in the Checkoutable listener fired');
|
||||||
@@ -145,61 +142,54 @@ class CheckoutableListener
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$shouldSendEmailToUser = $this->checkoutableCategoryShouldSendEmail($event->checkoutable);
|
||||||
* Send the appropriate notification
|
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress();
|
||||||
*/
|
$shouldSendWebhookNotification = $this->shouldSendWebhookNotification();
|
||||||
if ($event->checkedOutTo && $event->checkoutable){
|
|
||||||
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
|
|
||||||
->where('assigned_to_id', $event->checkedOutTo->id)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
foreach($acceptances as $acceptance){
|
if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress && !$shouldSendWebhookNotification) {
|
||||||
if($acceptance->isPending()){
|
return;
|
||||||
$acceptance->delete();
|
}
|
||||||
|
|
||||||
|
if ($shouldSendEmailToUser || $shouldSendEmailToAlertAddress) {
|
||||||
|
/**
|
||||||
|
* Send the appropriate notification
|
||||||
|
*/
|
||||||
|
if ($event->checkedOutTo && $event->checkoutable) {
|
||||||
|
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
|
||||||
|
->where('assigned_to_id', $event->checkedOutTo->id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($acceptances as $acceptance) {
|
||||||
|
if ($acceptance->isPending()) {
|
||||||
|
$acceptance->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$settings = Setting::getSettings();
|
|
||||||
$adminCcEmailsArray = [];
|
|
||||||
|
|
||||||
if($settings->admin_cc_email !== '') {
|
$mailable = $this->getCheckinMailType($event);
|
||||||
$adminCcEmail = $settings->admin_cc_email;
|
$notifiable = $this->getNotifiableUser($event);
|
||||||
$adminCcEmailsArray = array_map('trim', explode(',', $adminCcEmail));
|
|
||||||
}
|
|
||||||
$ccEmails = array_filter($adminCcEmailsArray);
|
|
||||||
$mailable = $this->getCheckinMailType($event);
|
|
||||||
$notifiable = $this->getNotifiableUsers($event);
|
|
||||||
|
|
||||||
// Send email notifications
|
$notifiableHasEmail = $notifiable instanceof User && $notifiable->email;
|
||||||
try {
|
|
||||||
/**
|
|
||||||
* Send an email if any of the following conditions are met:
|
|
||||||
* 1. The asset requires acceptance
|
|
||||||
* 2. The item has a EULA
|
|
||||||
* 3. The item should send an email at check-in/check-out
|
|
||||||
* 4. If the admin CC email is set, even if the item being checked in doesn't have an email address (location, etc)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Send a checkout email to the admin's CC addresses, even if the target has no email
|
$shouldSendEmailToUser = $shouldSendEmailToUser && $notifiableHasEmail;
|
||||||
if (!empty($ccEmails)) {
|
|
||||||
Mail::to($ccEmails)->send($mailable);
|
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
|
||||||
Log::info('Checkin Mail sent to CC addresses');
|
|
||||||
|
try {
|
||||||
|
if (!empty($to)) {
|
||||||
|
Mail::to(array_flatten($to))->cc(array_flatten($cc))->send($mailable);
|
||||||
|
Log::info('Checkin Mail sent to CC addresses');
|
||||||
|
}
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a checkout email to the target if it has an email
|
|
||||||
if (!empty($notifiable->email)) {
|
|
||||||
Mail::to($notifiable)->send($mailable);
|
|
||||||
Log::info('Checkin Mail sent to checkout target');
|
|
||||||
}
|
|
||||||
} catch (ClientException $e) {
|
|
||||||
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send Webhook notification
|
if ($shouldSendWebhookNotification) {
|
||||||
try {
|
// Send Webhook notification
|
||||||
if ($this->shouldSendWebhookNotification()) {
|
try {
|
||||||
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
if ($this->newMicrosoftTeamsWebhookEnabled()) {
|
||||||
$message = $this->getCheckinNotification($event)->toMicrosoftTeams();
|
$message = $this->getCheckinNotification($event)->toMicrosoftTeams();
|
||||||
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
|
||||||
@@ -208,25 +198,24 @@ class CheckoutableListener
|
|||||||
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
|
||||||
->notify($this->getCheckinNotification($event));
|
->notify($this->getCheckinNotification($event));
|
||||||
}
|
}
|
||||||
}
|
} catch (ClientException $e) {
|
||||||
} catch (ClientException $e) {
|
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
|
||||||
if (strpos($e->getMessage(), 'channel_not_found') !== false) {
|
Log::warning(Setting::getSettings()->webhook_selected . " notification failed: " . $e->getMessage());
|
||||||
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'));
|
||||||
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());
|
||||||
else {
|
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
|
||||||
Log::error("ClientException caught during checkin notification: " . $e->getMessage());
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::warning(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'));
|
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::warning(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'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a checkout acceptance
|
* Generates a checkout acceptance
|
||||||
@@ -239,6 +228,7 @@ class CheckoutableListener
|
|||||||
if ($checkedOutToType != "App\Models\User") {
|
if ($checkedOutToType != "App\Models\User") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$event->checkoutable->requireAcceptance()) {
|
if (!$event->checkoutable->requireAcceptance()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -246,15 +236,22 @@ class CheckoutableListener
|
|||||||
$acceptance = new CheckoutAcceptance;
|
$acceptance = new CheckoutAcceptance;
|
||||||
$acceptance->checkoutable()->associate($event->checkoutable);
|
$acceptance->checkoutable()->associate($event->checkoutable);
|
||||||
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
||||||
|
|
||||||
|
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
|
||||||
|
|
||||||
|
if ($category?->alert_on_response) {
|
||||||
|
$acceptance->alert_on_response_id = auth()->id();
|
||||||
|
}
|
||||||
|
|
||||||
$acceptance->save();
|
$acceptance->save();
|
||||||
|
|
||||||
return $acceptance;
|
return $acceptance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the appropriate notification for the event
|
* Get the appropriate notification for the event
|
||||||
*
|
*
|
||||||
* @param CheckoutableCheckedIn $event
|
* @param CheckoutableCheckedIn $event
|
||||||
* @return Notification
|
* @return Notification
|
||||||
*/
|
*/
|
||||||
private function getCheckinNotification($event)
|
private function getCheckinNotification($event)
|
||||||
@@ -268,7 +265,7 @@ class CheckoutableListener
|
|||||||
break;
|
break;
|
||||||
case Asset::class:
|
case Asset::class:
|
||||||
$notificationClass = CheckinAssetNotification::class;
|
$notificationClass = CheckinAssetNotification::class;
|
||||||
break;
|
break;
|
||||||
case LicenseSeat::class:
|
case LicenseSeat::class:
|
||||||
$notificationClass = CheckinLicenseSeatNotification::class;
|
$notificationClass = CheckinLicenseSeatNotification::class;
|
||||||
break;
|
break;
|
||||||
@@ -276,9 +273,8 @@ class CheckoutableListener
|
|||||||
|
|
||||||
Log::debug('Notification class: '.$notificationClass);
|
Log::debug('Notification class: '.$notificationClass);
|
||||||
|
|
||||||
return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
|
return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the appropriate notification for the event
|
* Get the appropriate notification for the event
|
||||||
*
|
*
|
||||||
@@ -320,6 +316,7 @@ class CheckoutableListener
|
|||||||
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note);
|
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCheckinMailType($event){
|
private function getCheckinMailType($event){
|
||||||
$lookup = [
|
$lookup = [
|
||||||
Accessory::class => CheckinAccessoryMail::class,
|
Accessory::class => CheckinAccessoryMail::class,
|
||||||
@@ -341,7 +338,8 @@ class CheckoutableListener
|
|||||||
* @param $event
|
* @param $event
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
private function getNotifiableUsers($event){
|
private function getNotifiableUser($event)
|
||||||
|
{
|
||||||
|
|
||||||
// If it's assigned to an asset, get that asset's assignedTo object
|
// If it's assigned to an asset, get that asset's assignedTo object
|
||||||
if ($event->checkedOutTo instanceof Asset){
|
if ($event->checkedOutTo instanceof Asset){
|
||||||
@@ -357,6 +355,7 @@ class CheckoutableListener
|
|||||||
return $event->checkedOutTo;
|
return $event->checkedOutTo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function webhookSelected(){
|
private function webhookSelected(){
|
||||||
if(Setting::getSettings()->webhook_selected === 'slack' || Setting::getSettings()->webhook_selected === 'general'){
|
if(Setting::getSettings()->webhook_selected === 'slack' || Setting::getSettings()->webhook_selected === 'general'){
|
||||||
return 'slack';
|
return 'slack';
|
||||||
@@ -365,60 +364,113 @@ class CheckoutableListener
|
|||||||
return Setting::getSettings()->webhook_selected;
|
return Setting::getSettings()->webhook_selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the listeners for the subscriber.
|
|
||||||
*
|
|
||||||
* @param Illuminate\Events\Dispatcher $events
|
|
||||||
*/
|
|
||||||
public function subscribe($events)
|
|
||||||
{
|
|
||||||
$events->listen(
|
|
||||||
\App\Events\CheckoutableCheckedIn::class,
|
|
||||||
'App\Listeners\CheckoutableListener@onCheckedIn'
|
|
||||||
);
|
|
||||||
|
|
||||||
$events->listen(
|
|
||||||
\App\Events\CheckoutableCheckedOut::class,
|
|
||||||
'App\Listeners\CheckoutableListener@onCheckedOut'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function shouldNotSendAnyNotifications($checkoutable): bool
|
private function shouldNotSendAnyNotifications($checkoutable): bool
|
||||||
{
|
{
|
||||||
if(in_array(get_class($checkoutable), $this->skipNotificationsFor)) {
|
return in_array(get_class($checkoutable), $this->skipNotificationsFor);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//runs a check if the category wants to send checkin/checkout emails to users
|
|
||||||
$category = match (true) {
|
|
||||||
$checkoutable instanceof Asset => $checkoutable->model->category,
|
|
||||||
$checkoutable instanceof Accessory,
|
|
||||||
$checkoutable instanceof Consumable => $checkoutable->category,
|
|
||||||
$checkoutable instanceof LicenseSeat => $checkoutable->license->category,
|
|
||||||
default => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!$category?->checkin_email) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function shouldSendWebhookNotification(): bool
|
private function shouldSendWebhookNotification(): bool
|
||||||
{
|
{
|
||||||
return Setting::getSettings() && Setting::getSettings()->webhook_endpoint;
|
return Setting::getSettings() && Setting::getSettings()->webhook_endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkoutableShouldSendEmail($event): bool
|
private function checkoutableCategoryShouldSendEmail(Model $checkoutable): bool
|
||||||
{
|
{
|
||||||
if($event->checkoutable instanceof LicenseSeat){
|
if ($checkoutable instanceof LicenseSeat) {
|
||||||
return $event->checkoutable->license->checkin_email();
|
return $checkoutable->license->checkin_email();
|
||||||
}
|
}
|
||||||
return (method_exists($event->checkoutable, 'checkin_email') && $event->checkoutable->checkin_email());
|
return (method_exists($checkoutable, 'checkin_email') && $checkoutable->checkin_email());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newMicrosoftTeamsWebhookEnabled(): bool
|
private function newMicrosoftTeamsWebhookEnabled(): bool
|
||||||
{
|
{
|
||||||
return Setting::getSettings()->webhook_selected === 'microsoft' && Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows');
|
return Setting::getSettings()->webhook_selected === 'microsoft' && Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function shouldSendCheckoutEmailToUser(Model $checkoutable): bool
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send an email if any of the following conditions are met:
|
||||||
|
* 1. The asset requires acceptance
|
||||||
|
* 2. The item has a EULA
|
||||||
|
* 3. The item should send an email at check-in/check-out
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ($checkoutable->requireAcceptance()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($checkoutable->getEula()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->checkoutableCategoryShouldSendEmail($checkoutable)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldSendEmailToAlertAddress($acceptance = null): bool
|
||||||
|
{
|
||||||
|
$setting = Setting::getSettings();
|
||||||
|
|
||||||
|
if (!$setting) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($acceptance) && !$setting->admin_cc_always) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $setting->admin_cc_email;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFormattedAlertAddresses(): array
|
||||||
|
{
|
||||||
|
$alertAddresses = Setting::getSettings()->admin_cc_email;
|
||||||
|
|
||||||
|
if ($alertAddresses !== '') {
|
||||||
|
return array_filter(array_map('trim', explode(',', $alertAddresses)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateEmailRecipients(
|
||||||
|
bool $shouldSendEmailToUser,
|
||||||
|
bool $shouldSendEmailToAlertAddress,
|
||||||
|
mixed $notifiable
|
||||||
|
): array {
|
||||||
|
$to = [];
|
||||||
|
$cc = [];
|
||||||
|
|
||||||
|
// if user && cc: to user, cc admin
|
||||||
|
if ($shouldSendEmailToUser && $shouldSendEmailToAlertAddress) {
|
||||||
|
$to[] = $notifiable;
|
||||||
|
$cc[] = $this->getFormattedAlertAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user && no cc: to user
|
||||||
|
if ($shouldSendEmailToUser && !$shouldSendEmailToAlertAddress) {
|
||||||
|
$to[] = $notifiable;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no user && cc: to admin
|
||||||
|
if (!$shouldSendEmailToUser && $shouldSendEmailToAlertAddress) {
|
||||||
|
$to[] = $this->getFormattedAlertAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($to, $cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCategoryFromCheckoutable(Model $checkoutable): ?Category
|
||||||
|
{
|
||||||
|
return match (true) {
|
||||||
|
$checkoutable instanceof Asset => $checkoutable->model->category,
|
||||||
|
$checkoutable instanceof Accessory,
|
||||||
|
$checkoutable instanceof Consumable => $checkoutable->category,
|
||||||
|
$checkoutable instanceof LicenseSeat => $checkoutable->license->category,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use Livewire\Component;
|
|||||||
|
|
||||||
class CategoryEditForm extends Component
|
class CategoryEditForm extends Component
|
||||||
{
|
{
|
||||||
|
public bool $alertOnResponse;
|
||||||
|
|
||||||
public $defaultEulaText;
|
public $defaultEulaText;
|
||||||
|
|
||||||
public $eulaText;
|
public $eulaText;
|
||||||
|
|||||||
@@ -35,10 +35,14 @@ class Importer extends Component
|
|||||||
public $accessories_fields;
|
public $accessories_fields;
|
||||||
public $assets_fields;
|
public $assets_fields;
|
||||||
public $users_fields;
|
public $users_fields;
|
||||||
|
public $assetmodels_fields;
|
||||||
|
public $suppliers_fields;
|
||||||
public $licenses_fields;
|
public $licenses_fields;
|
||||||
public $locations_fields;
|
public $locations_fields;
|
||||||
public $consumables_fields;
|
public $consumables_fields;
|
||||||
public $components_fields;
|
public $components_fields;
|
||||||
|
public $manufacturers_fields;
|
||||||
|
public $categories_fields;
|
||||||
public $aliases_fields;
|
public $aliases_fields;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
@@ -85,9 +89,6 @@ class Importer extends Component
|
|||||||
case 'component':
|
case 'component':
|
||||||
$results = $this->components_fields;
|
$results = $this->components_fields;
|
||||||
break;
|
break;
|
||||||
case 'consumable':
|
|
||||||
$results = $this->consumables_fields;
|
|
||||||
break;
|
|
||||||
case 'license':
|
case 'license':
|
||||||
$results = $this->licenses_fields;
|
$results = $this->licenses_fields;
|
||||||
break;
|
break;
|
||||||
@@ -97,8 +98,14 @@ class Importer extends Component
|
|||||||
case 'location':
|
case 'location':
|
||||||
$results = $this->locations_fields;
|
$results = $this->locations_fields;
|
||||||
break;
|
break;
|
||||||
case 'user':
|
case 'supplier':
|
||||||
$results = $this->users_fields;
|
$results = $this->suppliers_fields;
|
||||||
|
break;
|
||||||
|
case 'manufacturer':
|
||||||
|
$results = $this->manufacturers_fields;
|
||||||
|
break;
|
||||||
|
case 'category':
|
||||||
|
$results = $this->categories_fields;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$results = [];
|
$results = [];
|
||||||
@@ -128,7 +135,7 @@ class Importer extends Component
|
|||||||
//yes, this key *is* valid. Continue on to the next field.
|
//yes, this key *is* valid. Continue on to the next field.
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
//no, this key is *INVALID* for this import type. Better set it to null
|
//no, this key is *INVALID* for this import type. Better set it to null,
|
||||||
// and we'll hope that the $aliases_fields or something else picks it up.
|
// and we'll hope that the $aliases_fields or something else picks it up.
|
||||||
$this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh.
|
$this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh.
|
||||||
} // TODO - strictly speaking, this isn't necessary here I don't think.
|
} // TODO - strictly speaking, this isn't necessary here I don't think.
|
||||||
@@ -149,7 +156,7 @@ class Importer extends Component
|
|||||||
// in "Accessories"!)
|
// in "Accessories"!)
|
||||||
if (array_key_exists($key, $this->columnOptions[$type])) {
|
if (array_key_exists($key, $this->columnOptions[$type])) {
|
||||||
$this->field_map[$i] = $key;
|
$this->field_map[$i] = $key;
|
||||||
continue 3; // bust out of both of these loops; as well as the surrounding one - e.g. move on to the next header
|
continue 3; // bust out of both of these loops and the surrounding one - e.g. move on to the next header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,6 +178,9 @@ class Importer extends Component
|
|||||||
'license' => trans('general.licenses'),
|
'license' => trans('general.licenses'),
|
||||||
'location' => trans('general.locations'),
|
'location' => trans('general.locations'),
|
||||||
'user' => trans('general.users'),
|
'user' => trans('general.users'),
|
||||||
|
'supplier' => trans('general.suppliers'),
|
||||||
|
'manufacturer' => trans('general.manufacturers'),
|
||||||
|
'category' => trans('general.categories'),
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,6 +203,7 @@ class Importer extends Component
|
|||||||
];
|
];
|
||||||
|
|
||||||
$this->assets_fields = [
|
$this->assets_fields = [
|
||||||
|
'id' => trans('general.id'),
|
||||||
'asset_eol_date' => trans('admin/hardware/form.eol_date'),
|
'asset_eol_date' => trans('admin/hardware/form.eol_date'),
|
||||||
'asset_model' => trans('general.model_name'),
|
'asset_model' => trans('general.model_name'),
|
||||||
'asset_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/general.asset')]),
|
'asset_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/general.asset')]),
|
||||||
@@ -319,6 +330,8 @@ class Importer extends Component
|
|||||||
'location' => trans('general.location'),
|
'location' => trans('general.location'),
|
||||||
'manager_first_name' => trans('general.importer.manager_first_name'),
|
'manager_first_name' => trans('general.importer.manager_first_name'),
|
||||||
'manager_last_name' => trans('general.importer.manager_last_name'),
|
'manager_last_name' => trans('general.importer.manager_last_name'),
|
||||||
|
'manager_employee_num' => trans('general.importer.manager_employee_num'),
|
||||||
|
'manager_username' => trans('general.importer.manager_username'),
|
||||||
'notes' => trans('general.notes'),
|
'notes' => trans('general.notes'),
|
||||||
'phone_number' => trans('admin/users/table.phone'),
|
'phone_number' => trans('admin/users/table.phone'),
|
||||||
'remote' => trans('admin/users/general.remote'),
|
'remote' => trans('admin/users/general.remote'),
|
||||||
@@ -332,6 +345,7 @@ class Importer extends Component
|
|||||||
|
|
||||||
$this->locations_fields = [
|
$this->locations_fields = [
|
||||||
'id' => trans('general.id'),
|
'id' => trans('general.id'),
|
||||||
|
'name' => trans('general.name'),
|
||||||
'address' => trans('general.address'),
|
'address' => trans('general.address'),
|
||||||
'address2' => trans('general.importer.address2'),
|
'address2' => trans('general.importer.address2'),
|
||||||
'city' => trans('general.city'),
|
'city' => trans('general.city'),
|
||||||
@@ -340,13 +354,52 @@ class Importer extends Component
|
|||||||
'ldap_ou' => trans('admin/locations/table.ldap_ou'),
|
'ldap_ou' => trans('admin/locations/table.ldap_ou'),
|
||||||
'manager' => trans('general.importer.manager_full_name'),
|
'manager' => trans('general.importer.manager_full_name'),
|
||||||
'manager_username' => trans('general.importer.manager_username'),
|
'manager_username' => trans('general.importer.manager_username'),
|
||||||
'name' => trans('general.item_name_var', ['item' => trans('general.location')]),
|
|
||||||
'notes' => trans('general.notes'),
|
'notes' => trans('general.notes'),
|
||||||
'parent_location' => trans('admin/locations/table.parent'),
|
'parent_location' => trans('admin/locations/table.parent'),
|
||||||
'state' => trans('general.state'),
|
'state' => trans('general.state'),
|
||||||
'zip' => trans('general.zip'),
|
'zip' => trans('general.zip'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$this->suppliers_fields = [
|
||||||
|
'id' => trans('general.id'),
|
||||||
|
'name' => trans('general.name'),
|
||||||
|
'address' => trans('general.address'),
|
||||||
|
'address2' => trans('general.importer.address2'),
|
||||||
|
'city' => trans('general.city'),
|
||||||
|
'notes' => trans('general.notes'),
|
||||||
|
'state' => trans('general.state'),
|
||||||
|
'zip' => trans('general.zip'),
|
||||||
|
'phone' => trans('general.phone'),
|
||||||
|
'fax' => trans('general.fax'),
|
||||||
|
'url' => trans('general.url'),
|
||||||
|
'contact' => trans('general.contact'),
|
||||||
|
'email' => trans('general.email'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->manufacturers_fields = [
|
||||||
|
'id' => trans('general.id'),
|
||||||
|
'name' => trans('general.name'),
|
||||||
|
'notes' => trans('general.notes'),
|
||||||
|
'support_phone' => trans('admin/manufacturers/table.support_phone'),
|
||||||
|
'support_url' => trans('admin/manufacturers/table.support_url'),
|
||||||
|
'support_email' => trans('admin/manufacturers/table.support_email'),
|
||||||
|
'warranty_lookup_url' => trans('admin/manufacturers/table.warranty_lookup_url'),
|
||||||
|
'url' => trans('general.url'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->categories_fields = [
|
||||||
|
'id' => trans('general.id'),
|
||||||
|
'name' => trans('general.name'),
|
||||||
|
'notes' => trans('general.notes'),
|
||||||
|
'category_type' => trans('admin/categories/general.import_category_type'),
|
||||||
|
'eula_text' => trans('admin/categories/general.import_eula_text'),
|
||||||
|
'use_default_eula' => trans('admin/categories/general.use_default_eula_column'),
|
||||||
|
'require_acceptance' => trans('admin/categories/general.import_require_acceptance'),
|
||||||
|
'checkin_email' => trans('admin/categories/general.import_checkin_email'),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->assetmodels_fields = [
|
$this->assetmodels_fields = [
|
||||||
'category' => trans('general.category'),
|
'category' => trans('general.category'),
|
||||||
'eol' => trans('general.eol'),
|
'eol' => trans('general.eol'),
|
||||||
@@ -371,6 +424,8 @@ class Importer extends Component
|
|||||||
'consumable name',
|
'consumable name',
|
||||||
'component name',
|
'component name',
|
||||||
'name',
|
'name',
|
||||||
|
'supplier name',
|
||||||
|
'location name',
|
||||||
],
|
],
|
||||||
'item_no' => [
|
'item_no' => [
|
||||||
'item number',
|
'item number',
|
||||||
|
|||||||
@@ -10,15 +10,16 @@ class LocationScopeCheck extends Component
|
|||||||
{
|
{
|
||||||
public $mismatched = [];
|
public $mismatched = [];
|
||||||
public $setting;
|
public $setting;
|
||||||
|
public $is_tested = false;
|
||||||
|
|
||||||
public function check_locations()
|
public function check_locations()
|
||||||
{
|
{
|
||||||
$this->mismatched = Helper::test_locations_fmcs(false);
|
$this->mismatched = Helper::test_locations_fmcs(false);
|
||||||
|
$this->is_tested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mount() {
|
public function mount() {
|
||||||
$this->setting = Setting::getSettings();
|
$this->setting = Setting::getSettings();
|
||||||
$this->mismatched = Helper::test_locations_fmcs(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
|||||||
@@ -71,12 +71,12 @@ class SlackSettingsForm extends Component
|
|||||||
|
|
||||||
$this->setting = Setting::getSettings();
|
$this->setting = Setting::getSettings();
|
||||||
$this->save_button = trans('general.save');
|
$this->save_button = trans('general.save');
|
||||||
$this->webhook_selected = $this->setting->webhook_selected;
|
$this->webhook_selected = ($this->setting->webhook_selected !== '') ? $this->setting->webhook_selected : 'slack';
|
||||||
$this->webhook_name = $this->webhook_text[$this->setting->webhook_selected]["name"];
|
$this->webhook_name = $this->webhook_text[$this->setting->webhook_selected]["name"] ?? $this->webhook_text['slack']["name"];
|
||||||
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"];
|
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"] ?? $this->webhook_text['slack']["icon"];
|
||||||
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"];
|
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"] ?? $this->webhook_text['slack']["placeholder"];
|
||||||
$this->webhook_link = $this->webhook_text[$this->setting->webhook_selected]["link"];
|
$this->webhook_link = $this->webhook_text[$this->setting->webhook_selected]["link"] ?? $this->webhook_text['slack']["link"];
|
||||||
$this->webhook_test = $this->webhook_text[$this->setting->webhook_selected]["test"];
|
$this->webhook_test = $this->webhook_text[$this->setting->webhook_selected]["test"] ?? $this->webhook_text['slack']["test"];
|
||||||
$this->webhook_endpoint = $this->setting->webhook_endpoint;
|
$this->webhook_endpoint = $this->setting->webhook_endpoint;
|
||||||
$this->webhook_channel = $this->setting->webhook_channel;
|
$this->webhook_channel = $this->setting->webhook_channel;
|
||||||
$this->webhook_botname = $this->setting->webhook_botname;
|
$this->webhook_botname = $this->setting->webhook_botname;
|
||||||
@@ -90,7 +90,7 @@ class SlackSettingsForm extends Component
|
|||||||
$this->isDisabled= '';
|
$this->isDisabled= '';
|
||||||
}
|
}
|
||||||
if($this->webhook_selected === 'microsoft' && $this->teams_webhook_deprecated) {
|
if($this->webhook_selected === 'microsoft' && $this->teams_webhook_deprecated) {
|
||||||
session()->flash('warning', 'The selected Microsoft Teams webhook URL will be deprecated Jan 31st, 2025. Please use a workflow URL. Microsofts Documentation on creating a workflow can be found <a href="https://support.microsoft.com/en-us/office/create-incoming-webhooks-with-workflows-for-microsoft-teams-8ae491c7-0394-4861-ba59-055e33f75498" target="_blank"> here.</a>');
|
session()->flash('warning', trans('admin/settings/message.webhook.ms_teams_deprecation'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function updated($field) {
|
public function updated($field) {
|
||||||
|
|||||||
79
app/Mail/CheckoutAcceptanceResponseMail.php
Normal file
79
app/Mail/CheckoutAcceptanceResponseMail.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use App\Models\CheckoutAcceptance;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CheckoutAcceptanceResponseMail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public CheckoutAcceptance $acceptance;
|
||||||
|
public User $recipient;
|
||||||
|
public bool $wasAccepted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct(CheckoutAcceptance $acceptance, User $recipient, bool $wasAccepted)
|
||||||
|
{
|
||||||
|
$this->acceptance = $acceptance;
|
||||||
|
$this->recipient = $recipient;
|
||||||
|
$this->wasAccepted = $wasAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
$subject = $this->wasAccepted
|
||||||
|
? trans('mail.initiated_accepted')
|
||||||
|
: trans('mail.initiated_declined');
|
||||||
|
|
||||||
|
return new Envelope(
|
||||||
|
subject: $subject,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'mail.markdown.checkout-acceptance-response',
|
||||||
|
with: [
|
||||||
|
'assignedTo' => $this->acceptance->assignedTo,
|
||||||
|
'introduction' => $this->introduction(),
|
||||||
|
'item' => $this->acceptance->checkoutable,
|
||||||
|
'note' => $this->acceptance->note,
|
||||||
|
'recipient' => $this->recipient,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function introduction(): string
|
||||||
|
{
|
||||||
|
return $this->wasAccepted
|
||||||
|
? trans('mail.following_accepted')
|
||||||
|
: trans('mail.following_declined');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -14,7 +15,7 @@ use Watson\Validating\ValidatingTrait;
|
|||||||
/**
|
/**
|
||||||
* Model for Accessories.
|
* Model for Accessories.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class Accessory extends SnipeModel
|
class Accessory extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -22,6 +23,7 @@ class Accessory extends SnipeModel
|
|||||||
|
|
||||||
protected $presenter = \App\Presenters\AccessoryPresenter::class;
|
protected $presenter = \App\Presenters\AccessoryPresenter::class;
|
||||||
use CompanyableTrait;
|
use CompanyableTrait;
|
||||||
|
use HasUploads;
|
||||||
use Loggable, Presentable;
|
use Loggable, Presentable;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
|
|
||||||
@@ -54,8 +56,8 @@ class Accessory extends SnipeModel
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessory validation rules
|
* Accessory validation rules
|
||||||
*/
|
*/
|
||||||
public $rules = [
|
public $rules = [
|
||||||
'name' => 'required|min:3|max:255',
|
'name' => 'required|min:3|max:255',
|
||||||
'qty' => 'required|integer|min:1',
|
'qty' => 'required|integer|min:1',
|
||||||
@@ -69,12 +71,12 @@ class Accessory extends SnipeModel
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the model should inject it's identifier to the unique
|
* Whether the model should inject it's identifier to the unique
|
||||||
* validation rules before attempting validation. If this property
|
* validation rules before attempting validation. If this property
|
||||||
* is not set in the model it will default to true.
|
* is not set in the model it will default to true.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $injectUniqueIdentifier = true;
|
protected $injectUniqueIdentifier = true;
|
||||||
use ValidatingTrait;
|
use ValidatingTrait;
|
||||||
|
|
||||||
@@ -102,29 +104,11 @@ class Accessory extends SnipeModel
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Establishes the accessories -> action logs -> uploads relationship
|
|
||||||
*
|
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
|
||||||
* @since [v6.1.13]
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
|
||||||
*/
|
|
||||||
public function uploads()
|
|
||||||
{
|
|
||||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
|
||||||
->where('item_type', '=', self::class)
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->whereNotNull('filename')
|
|
||||||
->orderBy('created_at', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the accessory -> supplier relationship
|
* Establishes the accessory -> supplier relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function supplier()
|
public function supplier()
|
||||||
@@ -137,7 +121,7 @@ class Accessory extends SnipeModel
|
|||||||
* Sets the requestable attribute on the accessory
|
* Sets the requestable attribute on the accessory
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setRequestableAttribute($value)
|
public function setRequestableAttribute($value)
|
||||||
@@ -152,7 +136,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> company relationship
|
* Establishes the accessory -> company relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function company()
|
public function company()
|
||||||
@@ -164,7 +148,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> location relationship
|
* Establishes the accessory -> location relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
@@ -176,7 +160,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> category relationship
|
* Establishes the accessory -> category relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function category()
|
public function category()
|
||||||
@@ -188,7 +172,7 @@ class Accessory extends SnipeModel
|
|||||||
* Returns the action logs associated with the accessory
|
* Returns the action logs associated with the accessory
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assetlog()
|
public function assetlog()
|
||||||
@@ -217,8 +201,8 @@ class Accessory extends SnipeModel
|
|||||||
*
|
*
|
||||||
* It's super-mega-assy, but it's the best I could do for now.
|
* It's super-mega-assy, but it's the best I could do for now.
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since v5.0.0
|
* @since v5.0.0
|
||||||
*
|
*
|
||||||
* @see \App\Http\Controllers\Api\AccessoriesController\checkedout()
|
* @see \App\Http\Controllers\Api\AccessoriesController\checkedout()
|
||||||
*/
|
*/
|
||||||
@@ -235,7 +219,7 @@ class Accessory extends SnipeModel
|
|||||||
* presenter or service provider
|
* presenter or service provider
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getImageUrl()
|
public function getImageUrl()
|
||||||
@@ -251,7 +235,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> users relationship
|
* Establishes the accessory -> users relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function checkouts()
|
public function checkouts()
|
||||||
@@ -264,7 +248,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> admin user relationship
|
* Establishes the accessory -> admin user relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v7.0.13]
|
* @since [v7.0.13]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -276,7 +260,7 @@ class Accessory extends SnipeModel
|
|||||||
* Checks whether or not the accessory has users
|
* Checks whether or not the accessory has users
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function hasUsers()
|
public function hasUsers()
|
||||||
@@ -290,7 +274,7 @@ class Accessory extends SnipeModel
|
|||||||
* Establishes the accessory -> manufacturer relationship
|
* Establishes the accessory -> manufacturer relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function manufacturer()
|
public function manufacturer()
|
||||||
@@ -303,12 +287,12 @@ class Accessory extends SnipeModel
|
|||||||
* accessory based on the category it belongs to.
|
* accessory based on the category it belongs to.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function checkin_email()
|
public function checkin_email()
|
||||||
{
|
{
|
||||||
return $this->category->checkin_email;
|
return $this->category?->checkin_email;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,7 +300,7 @@ class Accessory extends SnipeModel
|
|||||||
* accept it via email.
|
* accept it via email.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function requireAcceptance()
|
public function requireAcceptance()
|
||||||
@@ -329,7 +313,7 @@ class Accessory extends SnipeModel
|
|||||||
* checks for a settings level EULA
|
* checks for a settings level EULA
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getEula()
|
public function getEula()
|
||||||
@@ -349,7 +333,7 @@ class Accessory extends SnipeModel
|
|||||||
* Check how many items within an accessory are checked out
|
* Check how many items within an accessory are checked out
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numCheckedOut()
|
public function numCheckedOut()
|
||||||
@@ -366,7 +350,7 @@ class Accessory extends SnipeModel
|
|||||||
* bad things happen.
|
* bad things happen.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numRemaining()
|
public function numRemaining()
|
||||||
@@ -381,8 +365,8 @@ class Accessory extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Run after the checkout acceptance was declined by the user
|
* Run after the checkout acceptance was declined by the user
|
||||||
*
|
*
|
||||||
* @param User $acceptedBy
|
* @param User $acceptedBy
|
||||||
* @param string $signature
|
* @param string $signature
|
||||||
*/
|
*/
|
||||||
public function declinedCheckout(User $declinedBy, $signature)
|
public function declinedCheckout(User $declinedBy, $signature)
|
||||||
{
|
{
|
||||||
@@ -408,8 +392,8 @@ class Accessory extends SnipeModel
|
|||||||
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since v6.3.4
|
* @since v6.3.4
|
||||||
* @param $value
|
* @param $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setQtyAttribute($value)
|
public function setQtyAttribute($value)
|
||||||
@@ -426,7 +410,6 @@ class Accessory extends SnipeModel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on created_by name
|
* Query builder scope to order on created_by name
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function scopeOrderByCreatedByName($query, $order)
|
public function scopeOrderByCreatedByName($query, $order)
|
||||||
{
|
{
|
||||||
@@ -434,68 +417,68 @@ class Accessory extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeOrderCompany($query, $order)
|
public function scopeOrderCompany($query, $order)
|
||||||
{
|
{
|
||||||
return $query->leftJoin('companies', 'accessories.company_id', '=', 'companies.id')
|
return $query->leftJoin('companies', 'accessories.company_id', '=', 'companies.id')
|
||||||
->orderBy('companies.name', $order);
|
->orderBy('companies.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on category
|
* Query builder scope to order on category
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeOrderCategory($query, $order)
|
public function scopeOrderCategory($query, $order)
|
||||||
{
|
{
|
||||||
return $query->leftJoin('categories', 'accessories.category_id', '=', 'categories.id')
|
return $query->leftJoin('categories', 'accessories.category_id', '=', 'categories.id')
|
||||||
->orderBy('categories.name', $order);
|
->orderBy('categories.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on location
|
* Query builder scope to order on location
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeOrderLocation($query, $order)
|
public function scopeOrderLocation($query, $order)
|
||||||
{
|
{
|
||||||
return $query->leftJoin('locations', 'accessories.location_id', '=', 'locations.id')
|
return $query->leftJoin('locations', 'accessories.location_id', '=', 'locations.id')
|
||||||
->orderBy('locations.name', $order);
|
->orderBy('locations.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on manufacturer
|
* Query builder scope to order on manufacturer
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeOrderManufacturer($query, $order)
|
public function scopeOrderManufacturer($query, $order)
|
||||||
{
|
{
|
||||||
return $query->leftJoin('manufacturers', 'accessories.manufacturer_id', '=', 'manufacturers.id')->orderBy('manufacturers.name', $order);
|
return $query->leftJoin('manufacturers', 'accessories.manufacturer_id', '=', 'manufacturers.id')->orderBy('manufacturers.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on supplier
|
* Query builder scope to order on supplier
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeOrderSupplier($query, $order)
|
public function scopeOrderSupplier($query, $order)
|
||||||
{
|
{
|
||||||
return $query->leftJoin('suppliers', 'accessories.supplier_id', '=', 'suppliers.id')->orderBy('suppliers.name', $order);
|
return $query->leftJoin('suppliers', 'accessories.supplier_id', '=', 'suppliers.id')->orderBy('suppliers.name', $order);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use Watson\Validating\ValidatingTrait;
|
|||||||
/**
|
/**
|
||||||
* Model for Accessories.
|
* Model for Accessories.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class AccessoryCheckout extends Model
|
class AccessoryCheckout extends Model
|
||||||
{
|
{
|
||||||
@@ -36,7 +36,7 @@ class AccessoryCheckout extends Model
|
|||||||
* Establishes the accessory checkout -> accessory relationship
|
* Establishes the accessory checkout -> accessory relationship
|
||||||
*
|
*
|
||||||
* @author [A. Kroeger]
|
* @author [A. Kroeger]
|
||||||
* @since [v7.0.9]
|
* @since [v7.0.9]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function accessory()
|
public function accessory()
|
||||||
@@ -52,7 +52,7 @@ class AccessoryCheckout extends Model
|
|||||||
* Establishes the accessory checkout -> user relationship
|
* Establishes the accessory checkout -> user relationship
|
||||||
*
|
*
|
||||||
* @author [A. Kroeger]
|
* @author [A. Kroeger]
|
||||||
* @since [v7.0.9]
|
* @since [v7.0.9]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -64,7 +64,7 @@ class AccessoryCheckout extends Model
|
|||||||
* Get the target this asset is checked out to
|
* Get the target this asset is checked out to
|
||||||
*
|
*
|
||||||
* @author [A. Kroeger]
|
* @author [A. Kroeger]
|
||||||
* @since [v7.0]
|
* @since [v7.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assignedTo()
|
public function assignedTo()
|
||||||
@@ -76,7 +76,7 @@ class AccessoryCheckout extends Model
|
|||||||
* Gets the lowercased name of the type of target the asset is assigned to
|
* Gets the lowercased name of the type of target the asset is assigned to
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function assignedType()
|
public function assignedType()
|
||||||
@@ -91,7 +91,7 @@ class AccessoryCheckout extends Model
|
|||||||
* this method is an easy way of seeing if we are checked out to a user.
|
* this method is an easy way of seeing if we are checked out to a user.
|
||||||
*
|
*
|
||||||
* @author [A. Kroeger]
|
* @author [A. Kroeger]
|
||||||
* @since [v7.0]
|
* @since [v7.0]
|
||||||
*/
|
*/
|
||||||
public function checkedOutToUser(): bool
|
public function checkedOutToUser(): bool
|
||||||
{
|
{
|
||||||
@@ -127,50 +127,64 @@ class AccessoryCheckout extends Model
|
|||||||
* Run additional, advanced searches.
|
* Run additional, advanced searches.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
* @param array $terms The search terms
|
* @param array $terms The search terms
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
public function advancedTextSearch(Builder $query, array $terms)
|
public function advancedTextSearch(Builder $query, array $terms)
|
||||||
{
|
{
|
||||||
|
|
||||||
$userQuery = User::where(function ($query) use ($terms) {
|
$userQuery = User::where(
|
||||||
foreach ($terms as $term) {
|
function ($query) use ($terms) {
|
||||||
$search_str = '%' . $term . '%';
|
foreach ($terms as $term) {
|
||||||
$query->where('first_name', 'like', $search_str)
|
$search_str = '%' . $term . '%';
|
||||||
->orWhere('last_name', 'like', $search_str)
|
$query->where('first_name', 'like', $search_str)
|
||||||
->orWhere('note', 'like', $search_str);
|
->orWhere('last_name', 'like', $search_str)
|
||||||
|
->orWhere('note', 'like', $search_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})->select('id');
|
)->select('id');
|
||||||
|
|
||||||
$locationQuery = Location::where(function ($query) use ($terms) {
|
$locationQuery = Location::where(
|
||||||
foreach ($terms as $term) {
|
function ($query) use ($terms) {
|
||||||
$search_str = '%' . $term . '%';
|
foreach ($terms as $term) {
|
||||||
$query->where('name', 'like', $search_str);
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('name', 'like', $search_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})->select('id');
|
)->select('id');
|
||||||
|
|
||||||
$assetQuery = Asset::where(function ($query) use ($terms) {
|
$assetQuery = Asset::where(
|
||||||
foreach ($terms as $term) {
|
function ($query) use ($terms) {
|
||||||
$search_str = '%' . $term . '%';
|
foreach ($terms as $term) {
|
||||||
$query->where('name', 'like', $search_str);
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('name', 'like', $search_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})->select('id');
|
)->select('id');
|
||||||
|
|
||||||
$query->where(function ($query) use ($userQuery) {
|
$query->where(
|
||||||
$query->where('assigned_type', User::class)
|
function ($query) use ($userQuery) {
|
||||||
->whereIn('assigned_to', $userQuery);
|
$query->where('assigned_type', User::class)
|
||||||
})->orWhere(function($query) use ($locationQuery) {
|
->whereIn('assigned_to', $userQuery);
|
||||||
$query->where('assigned_type', Location::class)
|
|
||||||
->whereIn('assigned_to', $locationQuery);
|
|
||||||
})->orWhere(function($query) use ($assetQuery) {
|
|
||||||
$query->where('assigned_type', Asset::class)
|
|
||||||
->whereIn('assigned_to', $assetQuery);
|
|
||||||
})->orWhere(function($query) use ($terms) {
|
|
||||||
foreach ($terms as $term) {
|
|
||||||
$search_str = '%' . $term . '%';
|
|
||||||
$query->where('note', 'like', $search_str);
|
|
||||||
}
|
}
|
||||||
});
|
)->orWhere(
|
||||||
|
function ($query) use ($locationQuery) {
|
||||||
|
$query->where('assigned_type', Location::class)
|
||||||
|
->whereIn('assigned_to', $locationQuery);
|
||||||
|
}
|
||||||
|
)->orWhere(
|
||||||
|
function ($query) use ($assetQuery) {
|
||||||
|
$query->where('assigned_type', Asset::class)
|
||||||
|
->whereIn('assigned_to', $assetQuery);
|
||||||
|
}
|
||||||
|
)->orWhere(
|
||||||
|
function ($query) use ($terms) {
|
||||||
|
foreach ($terms as $term) {
|
||||||
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('note', 'like', $search_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
* Model for the Actionlog (the table that keeps a historical log of
|
* Model for the Actionlog (the table that keeps a historical log of
|
||||||
* checkouts, checkins, and updates).
|
* checkouts, checkins, and updates).
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class Actionlog extends SnipeModel
|
class Actionlog extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -69,8 +69,8 @@ class Actionlog extends SnipeModel
|
|||||||
*/
|
*/
|
||||||
protected $searchableRelations = [
|
protected $searchableRelations = [
|
||||||
'company' => ['name'],
|
'company' => ['name'],
|
||||||
'adminuser' => ['first_name','last_name','username', 'email'],
|
'adminuser' => ['first_name','last_name','username', 'email', 'employee_num'],
|
||||||
'user' => ['first_name','last_name','username', 'email'],
|
'user' => ['first_name','last_name','username', 'email', 'employee_num'],
|
||||||
'assets' => ['asset_tag','name', 'serial', 'order_number', 'notes', 'purchase_date'],
|
'assets' => ['asset_tag','name', 'serial', 'order_number', 'notes', 'purchase_date'],
|
||||||
'assets.model' => ['name', 'model_number', 'eol', 'notes'],
|
'assets.model' => ['name', 'model_number', 'eol', 'notes'],
|
||||||
'assets.model.category' => ['name', 'notes'],
|
'assets.model.category' => ['name', 'notes'],
|
||||||
@@ -96,24 +96,31 @@ class Actionlog extends SnipeModel
|
|||||||
* Override from Builder to automatically add the company
|
* Override from Builder to automatically add the company
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public static function boot()
|
public static function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
static::creating(function (self $actionlog) {
|
static::creating(
|
||||||
// If the admin is a superadmin, let's see if the target instead has a company.
|
function (self $actionlog) {
|
||||||
if (auth()->user() && auth()->user()->isSuperUser()) {
|
// If the admin is a superadmin, let's see if the target instead has a company.
|
||||||
if ($actionlog->target) {
|
if (auth()->user() && auth()->user()->isSuperUser()) {
|
||||||
$actionlog->company_id = $actionlog->target->company_id;
|
if ($actionlog->target) {
|
||||||
} elseif ($actionlog->item) {
|
$actionlog->company_id = $actionlog->target->company_id;
|
||||||
$actionlog->company_id = $actionlog->item->company_id;
|
} elseif ($actionlog->item) {
|
||||||
|
$actionlog->company_id = $actionlog->item->company_id;
|
||||||
|
}
|
||||||
|
} elseif (auth()->user() && auth()->user()->company) {
|
||||||
|
$actionlog->company_id = auth()->user()->company_id;
|
||||||
}
|
}
|
||||||
} elseif (auth()->user() && auth()->user()->company) {
|
|
||||||
$actionlog->company_id = auth()->user()->company_id;
|
if ($actionlog->action_date == '') {
|
||||||
|
$actionlog->action_date = Carbon::now();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +128,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> item relationship
|
* Establishes the actionlog -> item relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function item()
|
public function item()
|
||||||
@@ -133,7 +140,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> company relationship
|
* Establishes the actionlog -> company relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function company()
|
public function company()
|
||||||
@@ -146,7 +153,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> asset relationship
|
* Establishes the actionlog -> asset relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assets()
|
public function assets()
|
||||||
@@ -158,7 +165,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> license relationship
|
* Establishes the actionlog -> license relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function licenses()
|
public function licenses()
|
||||||
@@ -170,7 +177,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> consumable relationship
|
* Establishes the actionlog -> consumable relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function consumables()
|
public function consumables()
|
||||||
@@ -182,7 +189,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> consumable relationship
|
* Establishes the actionlog -> consumable relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function accessories()
|
public function accessories()
|
||||||
@@ -194,7 +201,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> components relationship
|
* Establishes the actionlog -> components relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function components()
|
public function components()
|
||||||
@@ -206,7 +213,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> item type relationship
|
* Establishes the actionlog -> item type relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function itemType()
|
public function itemType()
|
||||||
@@ -222,7 +229,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> target type relationship
|
* Establishes the actionlog -> target type relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function targetType()
|
public function targetType()
|
||||||
@@ -239,21 +246,21 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> uploads relationship
|
* Establishes the actionlog -> uploads relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function uploads()
|
public function uploads()
|
||||||
{
|
{
|
||||||
return $this->morphTo('item')
|
return $this->morphTo('item')
|
||||||
->where('action_type', '=', 'uploaded')
|
->where('action_type', '=', 'uploaded')
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the actionlog -> userlog relationship
|
* Establishes the actionlog -> userlog relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function userlog()
|
public function userlog()
|
||||||
@@ -265,20 +272,20 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> admin user relationship
|
* Establishes the actionlog -> admin user relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'created_by')
|
return $this->belongsTo(User::class, 'created_by')
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the actionlog -> user relationship
|
* Establishes the actionlog -> user relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function user()
|
public function user()
|
||||||
@@ -291,7 +298,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> target relationship
|
* Establishes the actionlog -> target relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function target()
|
public function target()
|
||||||
@@ -303,7 +310,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Establishes the actionlog -> location relationship
|
* Establishes the actionlog -> location relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
@@ -316,7 +323,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Check if the file exists, and if it does, force a download
|
* Check if the file exists, and if it does, force a download
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return string | false
|
* @return string | false
|
||||||
*/
|
*/
|
||||||
public function get_src($type = 'assets', $fieldname = 'filename')
|
public function get_src($type = 'assets', $fieldname = 'filename')
|
||||||
@@ -334,7 +341,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Saves the log record with the action type
|
* Saves the log record with the action type
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function logaction($actiontype)
|
public function logaction($actiontype)
|
||||||
@@ -355,7 +362,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Calculate the number of days until the next audit
|
* Calculate the number of days until the next audit
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function daysUntilNextAudit($monthInterval = 12, $asset = null)
|
public function daysUntilNextAudit($monthInterval = 12, $asset = null)
|
||||||
@@ -376,7 +383,7 @@ class Actionlog extends SnipeModel
|
|||||||
if ($this->created_at > $override_default_next) {
|
if ($this->created_at > $override_default_next) {
|
||||||
$next_audit_days = '-'.$next_audit_days;
|
$next_audit_days = '-'.$next_audit_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next_audit_days;
|
return $next_audit_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +391,7 @@ class Actionlog extends SnipeModel
|
|||||||
* Calculate the date of the next audit
|
* Calculate the date of the next audit
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Datetime
|
* @return \Datetime
|
||||||
*/
|
*/
|
||||||
public function calcNextAuditDate($monthInterval = 12, $asset = null)
|
public function calcNextAuditDate($monthInterval = 12, $asset = null)
|
||||||
@@ -401,24 +408,24 @@ class Actionlog extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Gets action logs in chronological order, excluding uploads
|
* Gets action logs in chronological order, excluding uploads
|
||||||
*
|
*
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @since v1.0
|
* @since v1.0
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
*/
|
*/
|
||||||
public function getListingOfActionLogsChronologicalOrder()
|
public function getListingOfActionLogsChronologicalOrder()
|
||||||
{
|
{
|
||||||
return $this->all()
|
return $this->all()
|
||||||
->where('action_type', '!=', 'uploaded')
|
->where('action_type', '!=', 'uploaded')
|
||||||
->orderBy('item_id', 'asc')
|
->orderBy('item_id', 'asc')
|
||||||
->orderBy('created_at', 'asc')
|
->orderBy('created_at', 'asc')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines what the type of request is so we can log it to the action_log
|
* Determines what the type of request is so we can log it to the action_log
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since v6.3.0
|
* @since v6.3.0
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function determineActionSource(): string
|
public function determineActionSource(): string
|
||||||
@@ -430,11 +437,12 @@ class Actionlog extends SnipeModel
|
|||||||
|
|
||||||
// This is an API call
|
// This is an API call
|
||||||
if (((request()->header('content-type') && (request()->header('accept'))=='application/json'))
|
if (((request()->header('content-type') && (request()->header('accept'))=='application/json'))
|
||||||
&& (starts_with(request()->header('authorization'), 'Bearer '))) {
|
&& (starts_with(request()->header('authorization'), 'Bearer '))
|
||||||
|
) {
|
||||||
return 'api';
|
return 'api';
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is probably NOT an API call
|
// This is probably NOT an API call
|
||||||
if (request()->filled('_token')) {
|
if (request()->filled('_token')) {
|
||||||
return 'gui';
|
return 'gui';
|
||||||
}
|
}
|
||||||
@@ -444,6 +452,62 @@ class Actionlog extends SnipeModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function uploads_file_url()
|
||||||
|
{
|
||||||
|
|
||||||
|
switch ($this->item_type) {
|
||||||
|
case Accessory::class:
|
||||||
|
return route('show.accessoryfile', [$this->item_id, $this->id]);
|
||||||
|
case Asset::class:
|
||||||
|
return route('show/assetfile', [$this->item_id, $this->id]);
|
||||||
|
case AssetModel::class:
|
||||||
|
return route('show/modelfile', [$this->item_id, $this->id]);
|
||||||
|
case Consumable::class:
|
||||||
|
return route('show/locationsfile', [$this->item_id, $this->id]);
|
||||||
|
case Component::class:
|
||||||
|
return route('show.componentfile', [$this->item_id, $this->id]);
|
||||||
|
case License::class:
|
||||||
|
return route('show.licensefile', [$this->item_id, $this->id]);
|
||||||
|
case Location::class:
|
||||||
|
return route('show/locationsfile', [$this->item_id, $this->id]);
|
||||||
|
case User::class:
|
||||||
|
return route('show/userfile', [$this->item_id, $this->id]);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploads_file_path()
|
||||||
|
{
|
||||||
|
|
||||||
|
switch ($this->item_type) {
|
||||||
|
case Accessory::class:
|
||||||
|
return 'private_uploads/accessories/'.$this->filename;
|
||||||
|
case Asset::class:
|
||||||
|
return 'private_uploads/assets/'.$this->filename;
|
||||||
|
case AssetModel::class:
|
||||||
|
return 'private_uploads/assetmodels/'.$this->filename;
|
||||||
|
case Consumable::class:
|
||||||
|
return 'private_uploads/consumables/'.$this->filename;
|
||||||
|
case Component::class:
|
||||||
|
return 'private_uploads/components/'.$this->filename;
|
||||||
|
case License::class:
|
||||||
|
return 'private_uploads/licenses/'.$this->filename;
|
||||||
|
case Location::class:
|
||||||
|
return 'private_uploads/locations/'.$this->filename;
|
||||||
|
case User::class:
|
||||||
|
return 'private_uploads/users/'.$this->filename;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Manually sets $this->source for determineActionSource()
|
// Manually sets $this->source for determineActionSource()
|
||||||
public function setActionSource($source = null): void
|
public function setActionSource($source = null): void
|
||||||
{
|
{
|
||||||
@@ -454,4 +518,4 @@ class Actionlog extends SnipeModel
|
|||||||
{
|
{
|
||||||
return $query->leftJoin('users as admin_sort', 'action_logs.created_by', '=', 'admin_sort.id')->select('action_logs.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
|
return $query->leftJoin('users as admin_sort', 'action_logs.created_by', '=', 'admin_sort.id')->select('action_logs.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1245
app/Models/Asset.php
1245
app/Models/Asset.php
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ use Watson\Validating\ValidatingTrait;
|
|||||||
/**
|
/**
|
||||||
* Model for Asset Maintenances.
|
* Model for Asset Maintenances.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class AssetMaintenance extends Model implements ICompanyableChild
|
class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
{
|
{
|
||||||
@@ -26,12 +26,12 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
protected $table = 'asset_maintenances';
|
protected $table = 'asset_maintenances';
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'asset_id' => 'required|integer',
|
'asset_id' => 'required|integer',
|
||||||
'supplier_id' => 'required|integer',
|
'supplier_id' => 'nullable|integer',
|
||||||
'asset_maintenance_type' => 'required',
|
'asset_maintenance_type' => 'required',
|
||||||
'title' => 'required|max:100',
|
'title' => 'required|max:100',
|
||||||
'is_warranty' => 'boolean',
|
'is_warranty' => 'boolean',
|
||||||
'start_date' => 'required|date_format:Y-m-d',
|
'start_date' => 'required|date_format:Y-m-d',
|
||||||
'completion_date' => 'date_format:Y-m-d|nullable',
|
'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date',
|
||||||
'notes' => 'string|nullable',
|
'notes' => 'string|nullable',
|
||||||
'cost' => 'numeric|nullable',
|
'cost' => 'numeric|nullable',
|
||||||
];
|
];
|
||||||
@@ -93,7 +93,7 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* getImprovementOptions
|
* getImprovementOptions
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
@@ -157,20 +157,21 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
* asset
|
* asset
|
||||||
* Get asset for this improvement
|
* Get asset for this improvement
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
public function asset()
|
public function asset()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(\App\Models\Asset::class, 'asset_id')
|
return $this->belongsTo(\App\Models\Asset::class, 'asset_id')
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the admin who created the maintenance
|
* Get the admin who created the maintenance
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @version v3.0
|
* @version v3.0
|
||||||
*/
|
*/
|
||||||
@@ -183,7 +184,7 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
public function supplier()
|
public function supplier()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id')
|
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id')
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -195,8 +196,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on a supplier
|
* Query builder scope to order on a supplier
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -211,8 +212,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on asset tag
|
* Query builder scope to order on asset tag
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -225,8 +226,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on asset tag
|
* Query builder scope to order on asset tag
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -239,8 +240,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on serial
|
* Query builder scope to order on serial
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -253,8 +254,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on status label name
|
* Query builder scope to order on status label name
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -265,6 +266,21 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||||||
->orderBy('maintained_asset_status.name', $order);
|
->orderBy('maintained_asset_status.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query builder scope to order on status label name
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
|
* @param text $order Order
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
|
*/
|
||||||
|
public function scopeOrderLocationName($query, $order)
|
||||||
|
{
|
||||||
|
return $query->join('assets as maintained_asset', 'asset_maintenances.asset_id', '=', 'maintained_asset.id')
|
||||||
|
->leftjoin('locations as maintained_asset_location', 'maintained_asset_location.id', '=', 'maintained_asset.location_id')
|
||||||
|
->orderBy('maintained_asset_location.name', $order);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on the user that created it
|
* Query builder scope to order on the user that created it
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -16,7 +17,7 @@ use App\Http\Traits\TwoColumnUniqueUndeletedTrait;
|
|||||||
* Model for Asset Models. Asset Models contain higher level
|
* Model for Asset Models. Asset Models contain higher level
|
||||||
* attributes that are common among the same type of asset.
|
* attributes that are common among the same type of asset.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class AssetModel extends SnipeModel
|
class AssetModel extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -24,6 +25,7 @@ class AssetModel extends SnipeModel
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use Loggable, Requestable, Presentable;
|
use Loggable, Requestable, Presentable;
|
||||||
use TwoColumnUniqueUndeletedTrait;
|
use TwoColumnUniqueUndeletedTrait;
|
||||||
|
use HasUploads;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the model should inject its identifier to the unique
|
* Whether the model should inject its identifier to the unique
|
||||||
@@ -103,7 +105,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Establishes the model -> assets relationship
|
* Establishes the model -> assets relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assets()
|
public function assets()
|
||||||
@@ -115,7 +117,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Establishes the model -> category relationship
|
* Establishes the model -> category relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function category()
|
public function category()
|
||||||
@@ -127,7 +129,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Establishes the model -> depreciation relationship
|
* Establishes the model -> depreciation relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function depreciation()
|
public function depreciation()
|
||||||
@@ -139,7 +141,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Establishes the model -> manufacturer relationship
|
* Establishes the model -> manufacturer relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function manufacturer()
|
public function manufacturer()
|
||||||
@@ -151,7 +153,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Establishes the model -> fieldset relationship
|
* Establishes the model -> fieldset relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function fieldset()
|
public function fieldset()
|
||||||
@@ -161,14 +163,14 @@ class AssetModel extends SnipeModel
|
|||||||
|
|
||||||
public function customFields()
|
public function customFields()
|
||||||
{
|
{
|
||||||
return $this->fieldset()->first()->fields();
|
return $this->fieldset()->first()->fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the model -> custom field default values relationship
|
* Establishes the model -> custom field default values relationship
|
||||||
*
|
*
|
||||||
* @author hannah tinkler
|
* @author hannah tinkler
|
||||||
* @since [v4.3]
|
* @since [v4.3]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function defaultValues()
|
public function defaultValues()
|
||||||
@@ -182,7 +184,7 @@ class AssetModel extends SnipeModel
|
|||||||
* @todo this should probably be moved
|
* @todo this should probably be moved
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function getImageUrl()
|
public function getImageUrl()
|
||||||
@@ -199,7 +201,7 @@ class AssetModel extends SnipeModel
|
|||||||
* Checks if the model is deletable
|
* Checks if the model is deletable
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v6.3.4]
|
* @since [v6.3.4]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isDeletable()
|
public function isDeletable()
|
||||||
@@ -209,27 +211,12 @@ class AssetModel extends SnipeModel
|
|||||||
&& ($this->deleted_at == '');
|
&& ($this->deleted_at == '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get uploads for this model
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v4.0]
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
|
||||||
*/
|
|
||||||
public function uploads()
|
|
||||||
{
|
|
||||||
return $this->hasMany('\App\Models\Actionlog', 'item_id')
|
|
||||||
->where('item_type', '=', AssetModel::class)
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->whereNotNull('filename')
|
|
||||||
->orderBy('created_at', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user who created the item
|
* Get user who created the item
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -248,10 +235,10 @@ class AssetModel extends SnipeModel
|
|||||||
* scopeInCategory
|
* scopeInCategory
|
||||||
* Get all models that are in the array of category ids
|
* Get all models that are in the array of category ids
|
||||||
*
|
*
|
||||||
* @param $query
|
* @param $query
|
||||||
* @param array $categoryIdListing
|
* @param array $categoryIdListing
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
@@ -264,9 +251,9 @@ class AssetModel extends SnipeModel
|
|||||||
* scopeRequestable
|
* scopeRequestable
|
||||||
* Get all models that are requestable by a user.
|
* Get all models that are requestable by a user.
|
||||||
*
|
*
|
||||||
* @param $query
|
* @param $query
|
||||||
*
|
*
|
||||||
* @return $query
|
* @return $query
|
||||||
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
||||||
* @version v3.5
|
* @version v3.5
|
||||||
*/
|
*/
|
||||||
@@ -278,8 +265,8 @@ class AssetModel extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to search on text, including catgeory and manufacturer name
|
* Query builder scope to search on text, including catgeory and manufacturer name
|
||||||
*
|
*
|
||||||
* @param Illuminate\Database\Query\Builder $query Query builder instance
|
* @param Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $search Search term
|
* @param text $search Search term
|
||||||
*
|
*
|
||||||
* @return Illuminate\Database\Query\Builder Modified query builder
|
* @return Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -287,23 +274,31 @@ class AssetModel extends SnipeModel
|
|||||||
{
|
{
|
||||||
return $query->where('models.name', 'LIKE', "%$search%")
|
return $query->where('models.name', 'LIKE', "%$search%")
|
||||||
->orWhere('model_number', 'LIKE', "%$search%")
|
->orWhere('model_number', 'LIKE', "%$search%")
|
||||||
->orWhere(function ($query) use ($search) {
|
->orWhere(
|
||||||
$query->whereHas('category', function ($query) use ($search) {
|
function ($query) use ($search) {
|
||||||
$query->where('categories.name', 'LIKE', '%'.$search.'%');
|
$query->whereHas(
|
||||||
});
|
'category', function ($query) use ($search) {
|
||||||
})
|
$query->where('categories.name', 'LIKE', '%'.$search.'%');
|
||||||
->orWhere(function ($query) use ($search) {
|
}
|
||||||
$query->whereHas('manufacturer', function ($query) use ($search) {
|
);
|
||||||
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
|
}
|
||||||
});
|
)
|
||||||
});
|
->orWhere(
|
||||||
|
function ($query) use ($search) {
|
||||||
|
$query->whereHas(
|
||||||
|
'manufacturer', function ($query) use ($search) {
|
||||||
|
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on manufacturer
|
* Query builder scope to order on manufacturer
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -315,8 +310,8 @@ class AssetModel extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on category name
|
* Query builder scope to order on category name
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -332,7 +327,6 @@ class AssetModel extends SnipeModel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on created_by name
|
* Query builder scope to order on created_by name
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function scopeOrderByCreatedByName($query, $order)
|
public function scopeOrderByCreatedByName($query, $order)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use Illuminate\Support\Str;
|
|||||||
* to require acceptance from the user, whether or not to
|
* to require acceptance from the user, whether or not to
|
||||||
* send a EULA to the user, etc.
|
* send a EULA to the user, etc.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class Category extends SnipeModel
|
class Category extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -32,6 +32,7 @@ class Category extends SnipeModel
|
|||||||
protected $hidden = ['created_by', 'deleted_at'];
|
protected $hidden = ['created_by', 'deleted_at'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
'alert_on_response' => 'boolean',
|
||||||
'created_by' => 'integer',
|
'created_by' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ class Category extends SnipeModel
|
|||||||
'eula_text',
|
'eula_text',
|
||||||
'name',
|
'name',
|
||||||
'require_acceptance',
|
'require_acceptance',
|
||||||
|
'alert_on_response',
|
||||||
'use_default_eula',
|
'use_default_eula',
|
||||||
'created_by',
|
'created_by',
|
||||||
'notes',
|
'notes',
|
||||||
@@ -94,12 +96,20 @@ class Category extends SnipeModel
|
|||||||
* Checks if category can be deleted
|
* Checks if category can be deleted
|
||||||
*
|
*
|
||||||
* @author [Dan Meltzer] [<dmeltzer.devel@gmail.com>]
|
* @author [Dan Meltzer] [<dmeltzer.devel@gmail.com>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isDeletable()
|
public function isDeletable()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// We have to check for models as well if the category type is asset
|
||||||
|
if ($this->category_type == 'asset') {
|
||||||
|
return Gate::allows('delete', $this)
|
||||||
|
&& ($this->itemCount() == 0)
|
||||||
|
&& ($this->models_count == 0)
|
||||||
|
&& ($this->deleted_at == '');
|
||||||
|
}
|
||||||
|
|
||||||
return Gate::allows('delete', $this)
|
return Gate::allows('delete', $this)
|
||||||
&& ($this->itemCount() == 0)
|
&& ($this->itemCount() == 0)
|
||||||
&& ($this->deleted_at == '');
|
&& ($this->deleted_at == '');
|
||||||
@@ -109,7 +119,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> accessories relationship
|
* Establishes the category -> accessories relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function accessories()
|
public function accessories()
|
||||||
@@ -121,7 +131,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> licenses relationship
|
* Establishes the category -> licenses relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.3]
|
* @since [v4.3]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function licenses()
|
public function licenses()
|
||||||
@@ -133,7 +143,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> consumables relationship
|
* Establishes the category -> consumables relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function consumables()
|
public function consumables()
|
||||||
@@ -145,7 +155,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> consumables relationship
|
* Establishes the category -> consumables relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function components()
|
public function components()
|
||||||
@@ -160,7 +170,7 @@ class Category extends SnipeModel
|
|||||||
* It should only be used in a single category context.
|
* It should only be used in a single category context.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function itemCount()
|
public function itemCount()
|
||||||
@@ -171,18 +181,18 @@ class Category extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch ($this->category_type) {
|
switch ($this->category_type) {
|
||||||
case 'asset':
|
case 'asset':
|
||||||
return $this->assets->count();
|
return $this->assets->count();
|
||||||
case 'accessory':
|
case 'accessory':
|
||||||
return $this->accessories->count();
|
return $this->accessories->count();
|
||||||
case 'component':
|
case 'component':
|
||||||
return $this->components->count();
|
return $this->components->count();
|
||||||
case 'consumable':
|
case 'consumable':
|
||||||
return $this->consumables->count();
|
return $this->consumables->count();
|
||||||
case 'license':
|
case 'license':
|
||||||
return $this->licenses->count();
|
return $this->licenses->count();
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -191,7 +201,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> assets relationship
|
* Establishes the category -> assets relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assets()
|
public function assets()
|
||||||
@@ -208,8 +218,8 @@ class Category extends SnipeModel
|
|||||||
* by their category.
|
* by their category.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.1.0]
|
* @since [v6.1.0]
|
||||||
* @see \App\Models\Asset::scopeAssetsForShow()
|
* @see \App\Models\Asset::scopeAssetsForShow()
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function showableAssets()
|
public function showableAssets()
|
||||||
@@ -221,7 +231,7 @@ class Category extends SnipeModel
|
|||||||
* Establishes the category -> models relationship
|
* Establishes the category -> models relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function models()
|
public function models()
|
||||||
@@ -239,7 +249,7 @@ class Category extends SnipeModel
|
|||||||
* checks for a settings level EULA
|
* checks for a settings level EULA
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return string | null
|
* @return string | null
|
||||||
*/
|
*/
|
||||||
public function getEula()
|
public function getEula()
|
||||||
@@ -266,7 +276,7 @@ class Category extends SnipeModel
|
|||||||
*
|
*
|
||||||
* This will also correctly parse a 1/0 if "true"/"false" is passed.
|
* This will also correctly parse a 1/0 if "true"/"false" is passed.
|
||||||
*
|
*
|
||||||
* @param $value
|
* @param $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setCheckinEmailAttribute($value)
|
public function setCheckinEmailAttribute($value)
|
||||||
@@ -283,9 +293,9 @@ class Category extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope for whether or not the category requires acceptance
|
* Query builder scope for whether or not the category requires acceptance
|
||||||
*
|
*
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
public function scopeRequiresAcceptance($query)
|
public function scopeRequiresAcceptance($query)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class CheckoutAcceptance extends Model
|
|||||||
protected $casts = [
|
protected $casts = [
|
||||||
'accepted_at' => 'datetime',
|
'accepted_at' => 'datetime',
|
||||||
'declined_at' => 'datetime',
|
'declined_at' => 'datetime',
|
||||||
|
'alert_on_response_id' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +66,7 @@ class CheckoutAcceptance extends Model
|
|||||||
/**
|
/**
|
||||||
* Was the checkoutable checked out to this user?
|
* Was the checkoutable checked out to this user?
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isCheckedOutTo(User $user)
|
public function isCheckedOutTo(User $user)
|
||||||
@@ -78,7 +79,7 @@ class CheckoutAcceptance extends Model
|
|||||||
* Do not add stuff here that doesn't have a corresponding column in the
|
* Do not add stuff here that doesn't have a corresponding column in the
|
||||||
* checkout_acceptances table or you'll get an error.
|
* checkout_acceptances table or you'll get an error.
|
||||||
*
|
*
|
||||||
* @param string $signature_filename
|
* @param string $signature_filename
|
||||||
*/
|
*/
|
||||||
public function accept($signature_filename, $eula = null, $filename = null, $note = null)
|
public function accept($signature_filename, $eula = null, $filename = null, $note = null)
|
||||||
{
|
{
|
||||||
@@ -98,7 +99,7 @@ class CheckoutAcceptance extends Model
|
|||||||
/**
|
/**
|
||||||
* Decline the checkout acceptance
|
* Decline the checkout acceptance
|
||||||
*
|
*
|
||||||
* @param string $signature_filename
|
* @param string $signature_filename
|
||||||
*/
|
*/
|
||||||
public function decline($signature_filename, $note = null)
|
public function decline($signature_filename, $note = null)
|
||||||
{
|
{
|
||||||
@@ -115,8 +116,9 @@ class CheckoutAcceptance extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter checkout acceptences by the user
|
* Filter checkout acceptences by the user
|
||||||
|
*
|
||||||
* @param Illuminate\Database\Eloquent\Builder $query
|
* @param Illuminate\Database\Eloquent\Builder $query
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
public function scopeForUser(Builder $query, User $user)
|
public function scopeForUser(Builder $query, User $user)
|
||||||
@@ -126,6 +128,7 @@ class CheckoutAcceptance extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter to only get pending acceptances
|
* Filter to only get pending acceptances
|
||||||
|
*
|
||||||
* @param Illuminate\Database\Eloquent\Builder $query
|
* @param Illuminate\Database\Eloquent\Builder $query
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ use Illuminate\Support\Facades\Schema;
|
|||||||
/**
|
/**
|
||||||
* Model for Companies.
|
* Model for Companies.
|
||||||
*
|
*
|
||||||
* @version v1.8
|
* @version v1.8
|
||||||
*/
|
*/
|
||||||
final class Company extends SnipeModel
|
final class Company extends SnipeModel
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
use CompanyableTrait;
|
||||||
|
|
||||||
|
|
||||||
protected $table = 'companies';
|
protected $table = 'companies';
|
||||||
|
|
||||||
@@ -26,19 +28,19 @@ final class Company extends SnipeModel
|
|||||||
'name' => 'required|min:1|max:255|unique:companies,name',
|
'name' => 'required|min:1|max:255|unique:companies,name',
|
||||||
'fax' => 'min:7|max:35|nullable',
|
'fax' => 'min:7|max:35|nullable',
|
||||||
'phone' => 'min:7|max:35|nullable',
|
'phone' => 'min:7|max:35|nullable',
|
||||||
'email' => 'email|max:150|nullable',
|
'email' => 'email|max:150|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $presenter = \App\Presenters\CompanyPresenter::class;
|
protected $presenter = \App\Presenters\CompanyPresenter::class;
|
||||||
use Presentable;
|
use Presentable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the model should inject it's identifier to the unique
|
* Whether the model should inject it's identifier to the unique
|
||||||
* validation rules before attempting validation. If this property
|
* validation rules before attempting validation. If this property
|
||||||
* is not set in the model it will default to true.
|
* is not set in the model it will default to true.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $injectUniqueIdentifier = true;
|
protected $injectUniqueIdentifier = true;
|
||||||
use ValidatingTrait;
|
use ValidatingTrait;
|
||||||
use Searchable;
|
use Searchable;
|
||||||
@@ -100,7 +102,7 @@ final class Company extends SnipeModel
|
|||||||
* account the full multiple company support setting
|
* account the full multiple company support setting
|
||||||
* and if the current user is a super user.
|
* and if the current user is a super user.
|
||||||
*
|
*
|
||||||
* @param $unescaped_input
|
* @param $unescaped_input
|
||||||
* @return int|mixed|string|null
|
* @return int|mixed|string|null
|
||||||
*/
|
*/
|
||||||
public static function getIdForCurrentUser($unescaped_input)
|
public static function getIdForCurrentUser($unescaped_input)
|
||||||
@@ -127,7 +129,7 @@ final class Company extends SnipeModel
|
|||||||
* Check to see if the current user should have access to the model.
|
* Check to see if the current user should have access to the model.
|
||||||
* I hate this method and I think it should be refactored.
|
* I hate this method and I think it should be refactored.
|
||||||
*
|
*
|
||||||
* @param $companyable
|
* @param $companyable
|
||||||
* @return bool|void
|
* @return bool|void
|
||||||
*/
|
*/
|
||||||
public static function isCurrentUserHasAccess($companyable)
|
public static function isCurrentUserHasAccess($companyable)
|
||||||
@@ -146,10 +148,10 @@ final class Company extends SnipeModel
|
|||||||
if (!is_string($companyable)) {
|
if (!is_string($companyable)) {
|
||||||
$company_table = $companyable->getModel()->getTable();
|
$company_table = $companyable->getModel()->getTable();
|
||||||
try {
|
try {
|
||||||
// This is primary for the gate:allows-check in location->isDeletable()
|
// This is primarily for the gate:allows-check in location->isDeletable()
|
||||||
// Locations don't have a company_id so without this it isn't possible to delete locations with FullMultipleCompanySupport enabled
|
// Locations don't have a company_id so without this it isn't possible to delete locations with FullMultipleCompanySupport enabled
|
||||||
// because this function is called by SnipePermissionsPolicy->before()
|
// because this function is called by SnipePermissionsPolicy->before()
|
||||||
if (!$companyable instanceof Company && !Schema::hasColumn($company_table, 'company_id')) {
|
if (!Schema::hasColumn($company_table, 'company_id')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +162,19 @@ final class Company extends SnipeModel
|
|||||||
|
|
||||||
|
|
||||||
if (auth()->user()) {
|
if (auth()->user()) {
|
||||||
Log::warning('Companyable is '.$companyable);
|
// Log::warning('Companyable is '.$companyable);
|
||||||
$current_user_company_id = auth()->user()->company_id;
|
$current_user_company_id = auth()->user()->company_id;
|
||||||
$companyable_company_id = $companyable->company_id;
|
$companyable_company_id = $companyable->company_id;
|
||||||
return $current_user_company_id == null || $current_user_company_id == $companyable_company_id || auth()->user()->isSuperUser();
|
|
||||||
|
// Set this to check companyable on company
|
||||||
|
if ($companyable instanceof Company) {
|
||||||
|
$companyable_company_id = $companyable->id;
|
||||||
|
}
|
||||||
|
return ($current_user_company_id == null) || ($current_user_company_id == $companyable_company_id) || auth()->user()->isSuperUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isCurrentUserAuthorized()
|
public static function isCurrentUserAuthorized()
|
||||||
@@ -183,7 +192,7 @@ final class Company extends SnipeModel
|
|||||||
* Checks if company can be deleted
|
* Checks if company can be deleted
|
||||||
*
|
*
|
||||||
* @author [Dan Meltzer] [<dmeltzer.devel@gmail.com>]
|
* @author [Dan Meltzer] [<dmeltzer.devel@gmail.com>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isDeletable()
|
public function isDeletable()
|
||||||
@@ -200,7 +209,7 @@ final class Company extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $unescaped_input
|
* @param $unescaped_input
|
||||||
* @return int|mixed|string|null
|
* @return int|mixed|string|null
|
||||||
*/
|
*/
|
||||||
public static function getIdForUser($unescaped_input)
|
public static function getIdForUser($unescaped_input)
|
||||||
@@ -256,14 +265,14 @@ final class Company extends SnipeModel
|
|||||||
* @todo - refactor that trait to handle the user's model as well.
|
* @todo - refactor that trait to handle the user's model as well.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] <snipe@snipe.net>
|
* @author [A. Gianotto] <snipe@snipe.net>
|
||||||
* @param $query
|
* @param $query
|
||||||
* @param $column
|
* @param $column
|
||||||
* @param $table_name
|
* @param $table_name
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function scopeCompanyables($query, $column = 'company_id', $table_name = null)
|
public static function scopeCompanyables($query, $column = 'company_id', $table_name = null)
|
||||||
{
|
{
|
||||||
// If not logged in and hitting this, assume we are on the command line and don't scope?'
|
// If not logged in and hitting this, assume we are on the command line and don't scope?
|
||||||
if (! static::isFullMultipleCompanySupportEnabled() || (Auth::hasUser() && auth()->user()->isSuperUser()) || (! Auth::hasUser())) {
|
if (! static::isFullMultipleCompanySupportEnabled() || (Auth::hasUser() && auth()->user()->isSuperUser()) || (! Auth::hasUser())) {
|
||||||
return $query;
|
return $query;
|
||||||
} else {
|
} else {
|
||||||
@@ -280,11 +289,16 @@ final class Company extends SnipeModel
|
|||||||
private static function scopeCompanyablesDirectly($query, $column = 'company_id', $table_name = null)
|
private static function scopeCompanyablesDirectly($query, $column = 'company_id', $table_name = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$company_id = null;
|
||||||
// Get the company ID of the logged-in user, or set it to null if there is no company associated with the user
|
// Get the company ID of the logged-in user, or set it to null if there is no company associated with the user
|
||||||
if (Auth::hasUser()) {
|
if (Auth::hasUser()) {
|
||||||
$company_id = auth()->user()->company_id;
|
$company_id = auth()->user()->company_id;
|
||||||
} else {
|
}
|
||||||
$company_id = null;
|
|
||||||
|
|
||||||
|
// If we are scoping the companies table itself, look for the company.id
|
||||||
|
if ($query->getModel()->getTable() == 'companies') {
|
||||||
|
return $query->where('companies.id', '=', $company_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -297,6 +311,8 @@ final class Company extends SnipeModel
|
|||||||
return $query->where($table.$column, '=', $company_id);
|
return $query->where($table.$column, '=', $company_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -311,8 +327,8 @@ final class Company extends SnipeModel
|
|||||||
* This gets invoked by CompanyableChildScope, but I'm not sure what it does.
|
* This gets invoked by CompanyableChildScope, but I'm not sure what it does.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] <snipe@snipe.net>
|
* @author [A. Gianotto] <snipe@snipe.net>
|
||||||
* @param array $companyable_names
|
* @param array $companyable_names
|
||||||
* @param $query
|
* @param $query
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function scopeCompanyableChildren(array $companyable_names, $query)
|
public static function scopeCompanyableChildren(array $companyable_names, $query)
|
||||||
@@ -324,17 +340,18 @@ final class Company extends SnipeModel
|
|||||||
return $query;
|
return $query;
|
||||||
} else {
|
} else {
|
||||||
$f = function ($q) {
|
$f = function ($q) {
|
||||||
Log::debug('scopeCompanyablesDirectly firing ');
|
|
||||||
static::scopeCompanyablesDirectly($q);
|
static::scopeCompanyablesDirectly($q);
|
||||||
};
|
};
|
||||||
|
|
||||||
$q = $query->where(function ($q) use ($companyable_names, $f) {
|
$q = $query->where(
|
||||||
$q2 = $q->whereHas($companyable_names[0], $f);
|
function ($q) use ($companyable_names, $f) {
|
||||||
|
$q2 = $q->whereHas($companyable_names[0], $f);
|
||||||
|
|
||||||
for ($i = 1; $i < count($companyable_names); $i++) {
|
for ($i = 1; $i < count($companyable_names); $i++) {
|
||||||
$q2 = $q2->orWhereHas($companyable_names[$i], $f);
|
$q2 = $q2->orWhereHas($companyable_names[$i], $f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
return $q;
|
return $q;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ use Illuminate\Database\Eloquent\Scope;
|
|||||||
/**
|
/**
|
||||||
* Handle query scoping for full company support.
|
* Handle query scoping for full company support.
|
||||||
*
|
*
|
||||||
* @todo Move this to a more Laravel 5.2 esque way
|
* @todo Move this to a more Laravel 5.2 esque way
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
final class CompanyableChildScope implements Scope
|
final class CompanyableChildScope implements Scope
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Apply the scope to a given Eloquent query builder.
|
* Apply the scope to a given Eloquent query builder.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
* @param \Illuminate\Database\Eloquent\Builder $builder
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function apply(Builder $builder, Model $model)
|
public function apply(Builder $builder, Model $model)
|
||||||
@@ -31,7 +31,7 @@ final class CompanyableChildScope implements Scope
|
|||||||
* @todo IMPLEMENT
|
* @todo IMPLEMENT
|
||||||
* Remove the scope from the given Eloquent query builder.
|
* Remove the scope from the given Eloquent query builder.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
* @param \Illuminate\Database\Eloquent\Builder $builder
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function remove(Builder $builder)
|
public function remove(Builder $builder)
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ use Illuminate\Database\Eloquent\Scope;
|
|||||||
/**
|
/**
|
||||||
* Handle query scoping for full company support.
|
* Handle query scoping for full company support.
|
||||||
*
|
*
|
||||||
* @todo Move this to a more Laravel 5.2 esque way
|
* @todo Move this to a more Laravel 5.2 esque way
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
final class CompanyableScope implements Scope
|
final class CompanyableScope implements Scope
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Apply the scope to a given Eloquent query builder.
|
* Apply the scope to a given Eloquent query builder.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
* @param \Illuminate\Database\Eloquent\Builder $builder
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function apply(Builder $builder, Model $model)
|
public function apply(Builder $builder, Model $model)
|
||||||
@@ -29,7 +29,7 @@ final class CompanyableScope implements Scope
|
|||||||
* @todo IMPLEMENT
|
* @todo IMPLEMENT
|
||||||
* Remove the scope from the given Eloquent query builder.
|
* Remove the scope from the given Eloquent query builder.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
* @param \Illuminate\Database\Eloquent\Builder $builder
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function remove(Builder $builder)
|
public function remove(Builder $builder)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ trait CompanyableTrait
|
|||||||
* This trait is used to scope models to the current company. To use this scope on companyable models,
|
* This trait is used to scope models to the current company. To use this scope on companyable models,
|
||||||
* we use the "use Companyable;" statement at the top of the mode.
|
* we use the "use Companyable;" statement at the top of the mode.
|
||||||
*
|
*
|
||||||
* @see \App\Models\Company\Company::scopeCompanyables()
|
* @see \App\Models\Company\Company::scopeCompanyables()
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function bootCompanyableTrait()
|
public static function bootCompanyableTrait()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -12,7 +13,7 @@ use Watson\Validating\ValidatingTrait;
|
|||||||
/**
|
/**
|
||||||
* Model for Components.
|
* Model for Components.
|
||||||
*
|
*
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
*/
|
*/
|
||||||
class Component extends SnipeModel
|
class Component extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -20,6 +21,7 @@ class Component extends SnipeModel
|
|||||||
|
|
||||||
protected $presenter = \App\Presenters\ComponentPresenter::class;
|
protected $presenter = \App\Presenters\ComponentPresenter::class;
|
||||||
use CompanyableTrait;
|
use CompanyableTrait;
|
||||||
|
use HasUploads;
|
||||||
use Loggable, Presentable;
|
use Loggable, Presentable;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@@ -113,28 +115,13 @@ class Component extends SnipeModel
|
|||||||
&& ($this->deleted_at == '');
|
&& ($this->deleted_at == '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Establishes the components -> action logs -> uploads relationship
|
|
||||||
*
|
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
|
||||||
* @since [v6.1.13]
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
|
||||||
*/
|
|
||||||
public function uploads()
|
|
||||||
{
|
|
||||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
|
||||||
->where('item_type', '=', self::class)
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->whereNotNull('filename')
|
|
||||||
->orderBy('created_at', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the component -> location relationship
|
* Establishes the component -> location relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
@@ -146,7 +133,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the component -> assets relationship
|
* Establishes the component -> assets relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assets()
|
public function assets()
|
||||||
@@ -160,7 +147,7 @@ class Component extends SnipeModel
|
|||||||
* @todo this is probably not needed - refactor
|
* @todo this is probably not needed - refactor
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -172,7 +159,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the component -> company relationship
|
* Establishes the component -> company relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function company()
|
public function company()
|
||||||
@@ -184,7 +171,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the component -> category relationship
|
* Establishes the component -> category relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function category()
|
public function category()
|
||||||
@@ -196,7 +183,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the item -> supplier relationship
|
* Establishes the item -> supplier relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.1.1]
|
* @since [v6.1.1]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function supplier()
|
public function supplier()
|
||||||
@@ -209,7 +196,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the item -> manufacturer relationship
|
* Establishes the item -> manufacturer relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function manufacturer()
|
public function manufacturer()
|
||||||
@@ -221,7 +208,7 @@ class Component extends SnipeModel
|
|||||||
* Establishes the component -> action logs relationship
|
* Establishes the component -> action logs relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assetlog()
|
public function assetlog()
|
||||||
@@ -233,7 +220,7 @@ class Component extends SnipeModel
|
|||||||
* Check how many items within a component are checked out
|
* Check how many items within a component are checked out
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numCheckedOut()
|
public function numCheckedOut()
|
||||||
@@ -252,11 +239,12 @@ class Component extends SnipeModel
|
|||||||
*
|
*
|
||||||
* This allows us to get the assets with assigned components without the company restriction
|
* This allows us to get the assets with assigned components without the company restriction
|
||||||
*/
|
*/
|
||||||
public function uncontrainedAssets() {
|
public function uncontrainedAssets()
|
||||||
|
{
|
||||||
|
|
||||||
return $this->belongsToMany(\App\Models\Asset::class, 'components_assets')
|
return $this->belongsToMany(\App\Models\Asset::class, 'components_assets')
|
||||||
->withPivot('id', 'assigned_qty', 'created_at', 'created_by', 'note')
|
->withPivot('id', 'assigned_qty', 'created_at', 'created_by', 'note')
|
||||||
->withoutGlobalScope(new CompanyableScope);
|
->withoutGlobalScope(new CompanyableScope);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +253,7 @@ class Component extends SnipeModel
|
|||||||
* Check how many items within a component are remaining
|
* Check how many items within a component are remaining
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numRemaining()
|
public function numRemaining()
|
||||||
@@ -288,8 +276,8 @@ class Component extends SnipeModel
|
|||||||
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since v6.3.4
|
* @since v6.3.4
|
||||||
* @param $value
|
* @param $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setQtyAttribute($value)
|
public function setQtyAttribute($value)
|
||||||
@@ -307,8 +295,8 @@ class Component extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -320,8 +308,8 @@ class Component extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -333,8 +321,8 @@ class Component extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -346,8 +334,8 @@ class Component extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on supplier
|
* Query builder scope to order on supplier
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -359,8 +347,8 @@ class Component extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on manufacturer
|
* Query builder scope to order on manufacturer
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -29,6 +30,7 @@ class Consumable extends SnipeModel
|
|||||||
use Loggable, Presentable;
|
use Loggable, Presentable;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use Acceptable;
|
use Acceptable;
|
||||||
|
use HasUploads;
|
||||||
|
|
||||||
protected $table = 'consumables';
|
protected $table = 'consumables';
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@@ -111,21 +113,6 @@ class Consumable extends SnipeModel
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Establishes the components -> action logs -> uploads relationship
|
|
||||||
*
|
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
|
||||||
* @since [v6.1.13]
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
|
||||||
*/
|
|
||||||
public function uploads()
|
|
||||||
{
|
|
||||||
return $this->hasMany(Actionlog::class, 'item_id')
|
|
||||||
->where('item_type', '=', self::class)
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->whereNotNull('filename')
|
|
||||||
->orderBy('created_at', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,7 +125,7 @@ class Consumable extends SnipeModel
|
|||||||
* @todo Update this comment once it's been implemented
|
* @todo Update this comment once it's been implemented
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function setRequestableAttribute($value)
|
public function setRequestableAttribute($value)
|
||||||
@@ -153,7 +140,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the consumable -> admin user relationship
|
* Establishes the consumable -> admin user relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -165,7 +152,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> assignments relationship
|
* Establishes the component -> assignments relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function consumableAssignments()
|
public function consumableAssignments()
|
||||||
@@ -177,7 +164,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> company relationship
|
* Establishes the component -> company relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function company()
|
public function company()
|
||||||
@@ -189,7 +176,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> manufacturer relationship
|
* Establishes the component -> manufacturer relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function manufacturer()
|
public function manufacturer()
|
||||||
@@ -201,7 +188,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> location relationship
|
* Establishes the component -> location relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
@@ -213,7 +200,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> category relationship
|
* Establishes the component -> category relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function category()
|
public function category()
|
||||||
@@ -226,7 +213,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> action logs relationship
|
* Establishes the component -> action logs relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assetlog()
|
public function assetlog()
|
||||||
@@ -238,7 +225,7 @@ class Consumable extends SnipeModel
|
|||||||
* Gets the full image url for the consumable
|
* Gets the full image url for the consumable
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return string | false
|
* @return string | false
|
||||||
*/
|
*/
|
||||||
public function getImageUrl()
|
public function getImageUrl()
|
||||||
@@ -254,7 +241,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the component -> users relationship
|
* Establishes the component -> users relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
*/
|
*/
|
||||||
public function users() : Relation
|
public function users() : Relation
|
||||||
{
|
{
|
||||||
@@ -265,7 +252,7 @@ class Consumable extends SnipeModel
|
|||||||
* Establishes the item -> supplier relationship
|
* Establishes the item -> supplier relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.1.1]
|
* @since [v6.1.1]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function supplier()
|
public function supplier()
|
||||||
@@ -279,19 +266,19 @@ class Consumable extends SnipeModel
|
|||||||
* asset model category
|
* asset model category
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function checkin_email()
|
public function checkin_email()
|
||||||
{
|
{
|
||||||
return $this->category->checkin_email;
|
return $this->category?->checkin_email;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this asset requires acceptance by the assigned user
|
* Determine whether this asset requires acceptance by the assigned user
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function requireAcceptance()
|
public function requireAcceptance()
|
||||||
@@ -304,7 +291,7 @@ class Consumable extends SnipeModel
|
|||||||
* checks for a settings level EULA
|
* checks for a settings level EULA
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string | false
|
* @return string | false
|
||||||
*/
|
*/
|
||||||
public function getEula()
|
public function getEula()
|
||||||
@@ -322,7 +309,7 @@ class Consumable extends SnipeModel
|
|||||||
* Check how many items within a consumable are checked out
|
* Check how many items within a consumable are checked out
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numCheckedOut()
|
public function numCheckedOut()
|
||||||
@@ -334,7 +321,7 @@ class Consumable extends SnipeModel
|
|||||||
* Checks the number of available consumables
|
* Checks the number of available consumables
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function numRemaining()
|
public function numRemaining()
|
||||||
@@ -360,8 +347,8 @@ class Consumable extends SnipeModel
|
|||||||
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
* This simply checks that there is a value for quantity, and if there isn't, set it to 0.
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since v6.3.4
|
* @since v6.3.4
|
||||||
* @param $value
|
* @param $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setQtyAttribute($value)
|
public function setQtyAttribute($value)
|
||||||
@@ -378,8 +365,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -391,8 +378,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on location
|
* Query builder scope to order on location
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -404,8 +391,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on manufacturer
|
* Query builder scope to order on manufacturer
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -417,8 +404,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -430,8 +417,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on remaining
|
* Query builder scope to order on remaining
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param string $order Order
|
* @param string $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -444,8 +431,8 @@ class Consumable extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on supplier
|
* Query builder scope to order on supplier
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class CustomField extends Model
|
|||||||
* table instead of the assets table.
|
* table instead of the assets table.
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
*/
|
*/
|
||||||
public static $table_name = 'assets';
|
public static $table_name = 'assets';
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ class CustomField extends Model
|
|||||||
* do with previously existing values. - @snipe
|
* do with previously existing values. - @snipe
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function name_to_db_name($name)
|
public static function name_to_db_name($name)
|
||||||
@@ -120,66 +120,78 @@ class CustomField extends Model
|
|||||||
* to do it in the controllers.
|
* to do it in the controllers.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function boot()
|
public static function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
self::created(function ($custom_field) {
|
self::created(
|
||||||
|
function ($custom_field) {
|
||||||
|
|
||||||
// Column already exists on the assets table - nothing to do here.
|
// Column already exists on the assets table - nothing to do here.
|
||||||
// This *shouldn't* happen in the wild.
|
// This *shouldn't* happen in the wild.
|
||||||
if (Schema::hasColumn(self::$table_name, $custom_field->db_column)) {
|
if (Schema::hasColumn(self::$table_name, $custom_field->db_column)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the column name in the assets table
|
||||||
|
Schema::table(
|
||||||
|
self::$table_name, function ($table) use ($custom_field) {
|
||||||
|
$table->text($custom_field->convertUnicodeDbSlug())->nullable();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the db_column property in the custom fields table
|
||||||
|
$custom_field->db_column = $custom_field->convertUnicodeDbSlug();
|
||||||
|
$custom_field->save();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Update the column name in the assets table
|
self::updating(
|
||||||
Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
function ($custom_field) {
|
||||||
$table->text($custom_field->convertUnicodeDbSlug())->nullable();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the db_column property in the custom fields table
|
// Column already exists on the assets table - nothing to do here.
|
||||||
$custom_field->db_column = $custom_field->convertUnicodeDbSlug();
|
if ($custom_field->isDirty('name')) {
|
||||||
$custom_field->save();
|
if (Schema::hasColumn(self::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
||||||
});
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
self::updating(function ($custom_field) {
|
// Rename the field if the name has changed
|
||||||
|
Schema::table(
|
||||||
|
self::$table_name, function ($table) use ($custom_field) {
|
||||||
|
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save the updated column name to the custom fields table
|
||||||
|
$custom_field->db_column = $custom_field->convertUnicodeDbSlug();
|
||||||
|
$custom_field->save();
|
||||||
|
|
||||||
// Column already exists on the assets table - nothing to do here.
|
|
||||||
if ($custom_field->isDirty('name')) {
|
|
||||||
if (Schema::hasColumn(self::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename the field if the name has changed
|
|
||||||
Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
|
||||||
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save the updated column name to the custom fields table
|
|
||||||
$custom_field->db_column = $custom_field->convertUnicodeDbSlug();
|
|
||||||
$custom_field->save();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Drop the assets column if we've deleted it from custom fields
|
// Drop the assets column if we've deleted it from custom fields
|
||||||
self::deleting(function ($custom_field) {
|
self::deleting(
|
||||||
return Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
function ($custom_field) {
|
||||||
$table->dropColumn($custom_field->db_column);
|
return Schema::table(
|
||||||
});
|
self::$table_name, function ($table) use ($custom_field) {
|
||||||
});
|
$table->dropColumn($custom_field->db_column);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the customfield -> fieldset relationship
|
* Establishes the customfield -> fieldset relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function fieldset()
|
public function fieldset()
|
||||||
@@ -214,26 +226,26 @@ class CustomField extends Model
|
|||||||
public function displayFieldInCurrentForm($form_type = null)
|
public function displayFieldInCurrentForm($form_type = null)
|
||||||
{
|
{
|
||||||
switch ($form_type) {
|
switch ($form_type) {
|
||||||
case 'audit':
|
case 'audit':
|
||||||
return $this->displayFieldInAuditForm();
|
return $this->displayFieldInAuditForm();
|
||||||
case 'checkin':
|
case 'checkin':
|
||||||
return $this->displayFieldInCheckinForm();
|
return $this->displayFieldInCheckinForm();
|
||||||
case 'checkout':
|
case 'checkout':
|
||||||
return $this->displayFieldInCheckoutForm();
|
return $this->displayFieldInCheckoutForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function assetModels()
|
public function assetModels()
|
||||||
{
|
{
|
||||||
return $this->fieldset()->with('models')->get()->pluck('models')->flatten()->unique('id');
|
return $this->fieldset()->with('models')->get()->pluck('models')->flatten()->unique('id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the customfield -> admin user relationship
|
* Establishes the customfield -> admin user relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function user()
|
public function user()
|
||||||
@@ -245,7 +257,7 @@ class CustomField extends Model
|
|||||||
* Establishes the customfield -> default values relationship
|
* Establishes the customfield -> default values relationship
|
||||||
*
|
*
|
||||||
* @author Hannah Tinkler
|
* @author Hannah Tinkler
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function defaultValues()
|
public function defaultValues()
|
||||||
@@ -262,19 +274,23 @@ class CustomField extends Model
|
|||||||
*/
|
*/
|
||||||
public function defaultValue($modelId)
|
public function defaultValue($modelId)
|
||||||
{
|
{
|
||||||
return $this->defaultValues->filter(function ($item) use ($modelId) {
|
return $this->defaultValues->filter(
|
||||||
return $item->pivot->asset_model_id == $modelId;
|
function ($item) use ($modelId) {
|
||||||
})->map(function ($item) {
|
return $item->pivot->asset_model_id == $modelId;
|
||||||
return $item->pivot->default_value;
|
}
|
||||||
})->first();
|
)->map(
|
||||||
|
function ($item) {
|
||||||
|
return $item->pivot->default_value;
|
||||||
|
}
|
||||||
|
)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the format of the attribute
|
* Checks the format of the attribute
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param $value string
|
* @param $value string
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function check_format($value)
|
public function check_format($value)
|
||||||
@@ -286,7 +302,7 @@ class CustomField extends Model
|
|||||||
* Gets the DB column name.
|
* Gets the DB column name.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function db_column_name()
|
public function db_column_name()
|
||||||
@@ -302,7 +318,7 @@ class CustomField extends Model
|
|||||||
* user-friendly text in the dropdowns, and in the custom fields display.
|
* user-friendly text in the dropdowns, and in the custom fields display.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getFormatAttribute($value)
|
public function getFormatAttribute($value)
|
||||||
@@ -320,7 +336,7 @@ class CustomField extends Model
|
|||||||
* Format a value string as an array for select boxes and checkboxes.
|
* Format a value string as an array for select boxes and checkboxes.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function setFormatAttribute($value)
|
public function setFormatAttribute($value)
|
||||||
@@ -336,7 +352,7 @@ class CustomField extends Model
|
|||||||
* Format a value string as an array for select boxes and checkboxes.
|
* Format a value string as an array for select boxes and checkboxes.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function formatFieldValuesAsArray()
|
public function formatFieldValuesAsArray()
|
||||||
@@ -366,7 +382,7 @@ class CustomField extends Model
|
|||||||
* Check whether the field is encrypted
|
* Check whether the field is encrypted
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isFieldDecryptable($string)
|
public function isFieldDecryptable($string)
|
||||||
@@ -383,7 +399,7 @@ class CustomField extends Model
|
|||||||
* won't break the database.
|
* won't break the database.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function convertUnicodeDbSlug($original = null)
|
public function convertUnicodeDbSlug($original = null)
|
||||||
@@ -392,7 +408,7 @@ class CustomField extends Model
|
|||||||
$id = $this->id ? $this->id : 'xx';
|
$id = $this->id ? $this->id : 'xx';
|
||||||
|
|
||||||
if (! function_exists('transliterator_transliterate')) {
|
if (! function_exists('transliterator_transliterate')) {
|
||||||
$long_slug = '_snipeit_'.str_slug(mb_convert_encoding(trim($name),"UTF-8"), '_');
|
$long_slug = '_snipeit_'.str_slug(mb_convert_encoding(trim($name), "UTF-8"), '_');
|
||||||
} else {
|
} else {
|
||||||
$long_slug = '_snipeit_'.Utf8Slugger::slugify($name, '_');
|
$long_slug = '_snipeit_'.Utf8Slugger::slugify($name, '_');
|
||||||
}
|
}
|
||||||
@@ -402,9 +418,10 @@ class CustomField extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get validation rules for custom fields to use with Validator
|
* Get validation rules for custom fields to use with Validator
|
||||||
|
*
|
||||||
* @author [V. Cordes] [<volker@fdatek.de>]
|
* @author [V. Cordes] [<volker@fdatek.de>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v4.1.10]
|
* @since [v4.1.10]
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function validationRules($regex_format = null)
|
public function validationRules($regex_format = null)
|
||||||
@@ -418,6 +435,7 @@ class CustomField extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if there is a custom regex format type
|
* Check to see if there is a custom regex format type
|
||||||
|
*
|
||||||
* @see https://github.com/grokability/snipe-it/issues/5896
|
* @see https://github.com/grokability/snipe-it/issues/5896
|
||||||
*
|
*
|
||||||
* @author Wes Hulette <jwhulette@gmail.com>
|
* @author Wes Hulette <jwhulette@gmail.com>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class CustomFieldset extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validation rules
|
* Validation rules
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $rules = [
|
public $rules = [
|
||||||
@@ -39,7 +40,7 @@ class CustomFieldset extends Model
|
|||||||
* Establishes the fieldset -> field relationship
|
* Establishes the fieldset -> field relationship
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function fields()
|
public function fields()
|
||||||
@@ -51,7 +52,7 @@ class CustomFieldset extends Model
|
|||||||
* Establishes the fieldset -> models relationship
|
* Establishes the fieldset -> models relationship
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function models()
|
public function models()
|
||||||
@@ -63,7 +64,7 @@ class CustomFieldset extends Model
|
|||||||
* Establishes the fieldset -> admin user relationship
|
* Establishes the fieldset -> admin user relationship
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function user()
|
public function user()
|
||||||
@@ -76,14 +77,14 @@ class CustomFieldset extends Model
|
|||||||
if ($this->fields) {
|
if ($this->fields) {
|
||||||
|
|
||||||
switch ($form_type) {
|
switch ($form_type) {
|
||||||
case 'audit':
|
case 'audit':
|
||||||
return $this->fields->where('display_audit', '1')->count() > 0;
|
return $this->fields->where('display_audit', '1')->count() > 0;
|
||||||
case 'checkin':
|
case 'checkin':
|
||||||
return $this->fields->where('display_checkin', '1')->count() > 0;
|
return $this->fields->where('display_checkin', '1')->count() > 0;
|
||||||
case 'checkout':
|
case 'checkout':
|
||||||
return $this->fields->where('display_checkout', '1')->count() > 0;
|
return $this->fields->where('display_checkout', '1')->count() > 0;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ class CustomFieldset extends Model
|
|||||||
* custom field format
|
* custom field format
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function validation_rules()
|
public function validation_rules()
|
||||||
@@ -104,8 +105,9 @@ class CustomFieldset extends Model
|
|||||||
foreach ($this->fields as $field) {
|
foreach ($this->fields as $field) {
|
||||||
$rule = [];
|
$rule = [];
|
||||||
|
|
||||||
if (($field->field_encrypted != '1') ||
|
if (($field->field_encrypted != '1')
|
||||||
(($field->field_encrypted == '1') && (Gate::allows('admin')))) {
|
|| (($field->field_encrypted == '1') && (Gate::allows('admin')))
|
||||||
|
) {
|
||||||
$rule[] = ($field->pivot->required == '1') ? 'required' : 'nullable';
|
$rule[] = ($field->pivot->required == '1') ? 'required' : 'nullable';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class Department extends SnipeModel
|
|||||||
* Establishes the department -> company relationship
|
* Establishes the department -> company relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function company()
|
public function company()
|
||||||
@@ -84,7 +84,7 @@ class Department extends SnipeModel
|
|||||||
* Establishes the department -> users relationship
|
* Establishes the department -> users relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function users()
|
public function users()
|
||||||
@@ -96,7 +96,7 @@ class Department extends SnipeModel
|
|||||||
* Establishes the department -> manager relationship
|
* Establishes the department -> manager relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function manager()
|
public function manager()
|
||||||
@@ -108,7 +108,7 @@ class Department extends SnipeModel
|
|||||||
* Establishes the department -> location relationship
|
* Establishes the department -> location relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
@@ -119,8 +119,8 @@ class Department extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on location name
|
* Query builder scope to order on location name
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -132,8 +132,8 @@ class Department extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on manager name
|
* Query builder scope to order on manager name
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
@@ -145,8 +145,8 @@ class Department extends SnipeModel
|
|||||||
/**
|
/**
|
||||||
* Query builder scope to order on company
|
* Query builder scope to order on company
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
* @param text $order Order
|
* @param text $order Order
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -48,15 +48,15 @@ class Depreciable extends SnipeModel
|
|||||||
$depreciation = 0;
|
$depreciation = 0;
|
||||||
$setting = Setting::getSettings();
|
$setting = Setting::getSettings();
|
||||||
switch ($setting->depreciation_method) {
|
switch ($setting->depreciation_method) {
|
||||||
case 'half_1':
|
case 'half_1':
|
||||||
$depreciation = $this->getHalfYearDepreciatedValue(true);
|
$depreciation = $this->getHalfYearDepreciatedValue(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'half_2':
|
case 'half_2':
|
||||||
$depreciation = $this->getHalfYearDepreciatedValue(false);
|
$depreciation = $this->getHalfYearDepreciatedValue(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$depreciation = $this->getLinearDepreciatedValue();
|
$depreciation = $this->getLinearDepreciatedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ class Depreciable extends SnipeModel
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($months_passed >= $this->get_depreciation()->months){
|
if ($months_passed >= $this->get_depreciation()->months) {
|
||||||
//if there is a floor use it
|
//if there is a floor use it
|
||||||
if($this->get_depreciation()->depreciation_min) {
|
if($this->get_depreciation()->depreciation_min) {
|
||||||
|
|
||||||
@@ -93,14 +93,15 @@ class Depreciable extends SnipeModel
|
|||||||
return $current_value;
|
return $current_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMonthlyDepreciation(){
|
public function getMonthlyDepreciation()
|
||||||
|
{
|
||||||
|
|
||||||
return ($this->purchase_cost-$this->calculateDepreciation())/$this->get_depreciation()->months;
|
return ($this->purchase_cost-$this->calculateDepreciation())/$this->get_depreciation()->months;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param onlyHalfFirstYear Boolean always applied only second half of the first year
|
* @param onlyHalfFirstYear Boolean always applied only second half of the first year
|
||||||
* @return float|int
|
* @return float|int
|
||||||
*/
|
*/
|
||||||
public function getHalfYearDepreciatedValue($onlyHalfFirstYear = false)
|
public function getHalfYearDepreciatedValue($onlyHalfFirstYear = false)
|
||||||
@@ -131,7 +132,7 @@ class Depreciable extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \DateTime $date
|
* @param \DateTime $date
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
protected function get_fiscal_year($date)
|
protected function get_fiscal_year($date)
|
||||||
@@ -146,7 +147,7 @@ class Depreciable extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \DateTime $date
|
* @param \DateTime $date
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function is_first_half_of_year($date)
|
protected function is_first_half_of_year($date)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Depreciation extends SnipeModel
|
|||||||
// Declare the rules for the form validation
|
// Declare the rules for the form validation
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'name' => 'required|min:3|max:255|unique:depreciations,name',
|
'name' => 'required|min:3|max:255|unique:depreciations,name',
|
||||||
'months' => 'required|max:3600|integer|gt:0',
|
'months' => 'required|max:3600|integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +56,7 @@ class Depreciation extends SnipeModel
|
|||||||
* Establishes the depreciation -> models relationship
|
* Establishes the depreciation -> models relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function models()
|
public function models()
|
||||||
@@ -68,7 +68,7 @@ class Depreciation extends SnipeModel
|
|||||||
* Establishes the depreciation -> licenses relationship
|
* Establishes the depreciation -> licenses relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function licenses()
|
public function licenses()
|
||||||
@@ -80,7 +80,7 @@ class Depreciation extends SnipeModel
|
|||||||
* Establishes the depreciation -> assets relationship
|
* Establishes the depreciation -> assets relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function assets()
|
public function assets()
|
||||||
@@ -92,7 +92,7 @@ class Depreciation extends SnipeModel
|
|||||||
* Get the user that created the depreciation
|
* Get the user that created the depreciation
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v7.0.13]
|
* @since [v7.0.13]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Group extends SnipeModel
|
|||||||
* Establishes the groups -> users relationship
|
* Establishes the groups -> users relationship
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function users()
|
public function users()
|
||||||
@@ -63,7 +63,7 @@ class Group extends SnipeModel
|
|||||||
* Get the user that created the group
|
* Get the user that created the group
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v6.3.0]
|
* @since [v6.3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function adminuser()
|
public function adminuser()
|
||||||
@@ -75,7 +75,7 @@ class Group extends SnipeModel
|
|||||||
* Decode JSON permissions into array
|
* Decode JSON permissions into array
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return array | \stdClass
|
* @return array | \stdClass
|
||||||
*/
|
*/
|
||||||
public function decodePermissions()
|
public function decodePermissions()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user