Compare commits

...

1101 Commits

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

# Conflicts:
#	config/version.php
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	public/css/dist/skins/skin-black-dark.css
#	public/css/dist/skins/skin-black-dark.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/mix-manifest.json
2025-05-07 11:41:31 +01:00
snipe
a916767392 Show the QR code on the asset page regardless of label settings
Signed-off-by: snipe <snipe@snipe.net>
2025-05-07 11:34:21 +01:00
snipe
1c57bfaa39 Small cosmetic change to offset
Signed-off-by: snipe <snipe@snipe.net>
2025-05-07 11:28:01 +01:00
snipe
4a5adeb661 Fixed #16866 - use singular translation for custom report
Signed-off-by: snipe <snipe@snipe.net>
2025-05-07 10:55:28 +01:00
snipe
01f9772291 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2025-05-07 10:37:10 +01:00
snipe
960b3aebed Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2025-05-07 10:24:07 +01:00
snipe
e75df97902 Merge pull request #16876 from grokability/switch-back-to-multiarch-docker-with-emulation
Move back to multiarch builds with emulation (for now)
2025-05-06 21:39:23 +01:00
Jeremy Price
5be14ec750 Move back to multiarch builds with emulation (for now)
Turns out it's not straightforward to have multiarchitecture images
within the same namespace, if you want to run each architecture's build
on native runners.

While we work on getting that going, we're moving back to
build-everything-on-intel-runners-with-emulation-for-arm

it means slowwwww arm builds, but it also means we should get our images
straightened out
2025-05-06 22:27:53 +02:00
snipe
717a82f46a Dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-05-06 21:27:02 +01:00
snipe
e40038900b Merge pull request #16875 from ubc-cpsc/bugfix/CVE-2025-46734
Fixes CVE-2025-46734: league/commonmark contains a XSS vulnerability in Attributes extension
2025-05-06 19:19:09 +01:00
Joël Pittet
099eabc240 Fixes CVE-2025-46734 2025-05-06 11:01:45 -07:00
snipe
d67933ab49 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	.all-contributorsrc
#	CONTRIBUTORS.md
2025-05-06 16:46:41 +01:00
snipe
3a4fa35398 Merge pull request #16874 from grokability/clone_breadcrumb_fix
Fixed breadcrumbs for cloning
2025-05-06 16:42:52 +01:00
snipe
500d6a0cc2 Merge pull request #16873 from grokability/redirect_on_audit
Redirect options on audit
2025-05-06 16:39:29 +01:00
snipe
38e5bf71bc Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2025-05-06 16:36:09 +01:00
snipe
45ff195f11 Fixed breadcrumbs for cloning
Signed-off-by: snipe <snipe@snipe.net>
2025-05-06 16:17:02 +01:00
snipe
ce543c8179 Use consistent icon
Signed-off-by: snipe <snipe@snipe.net>
2025-05-06 16:12:15 +01:00
snipe
5c11a8c1e0 Modified helper
Signed-off-by: snipe <snipe@snipe.net>
2025-05-06 16:12:06 +01:00
snipe
f013a4c5ea Merge pull request #16871 from grokability/one-more-docker-fix
One more docker repo name fix
2025-05-06 15:16:48 +01:00
Jeremy Price
194a22452e stop building intel image in arm server 2025-05-06 16:10:44 +02:00
Jeremy Price
930a6a2ac8 One more docker repo name fix
i feel like i'm taking crazy pills

also right-naming the arm builds again
2025-05-06 16:06:13 +02:00
snipe
444dea8b42 Merge pull request #16868 from grokability/fix-dockerhub-references
OMG fix 2 more (only 1 active) dockerhub repo references
2025-05-06 10:15:28 +01:00
Jeremy Price
6cc3f69c2a OMG fix 2 more (only 1 active) dockerhub repo references 2025-05-06 07:54:20 +02:00
snipe
36f3834ca5 Merge pull request #16865 from ntaylor-86/fixes/alerts-enabled-new-install
Fixed #16815: Avoids potential error when settings table is empty
2025-05-06 00:59:52 +01:00
Nathan Taylor
d4b73b4fb9 Avoids potential error when alerts table is empty
Updates the Kernel to use the null-safe operator
when accessing the alerts_enabled setting. This prevents
a potential error if the settings object is null.
2025-05-06 09:47:33 +10:00
snipe
b37f488117 Merge pull request #16864 from marcusmoore/update-contributors
Added missing contributors
2025-05-05 22:18:11 +01:00
snipe
ee0a9e834a Fixed BulkDeleteAssetsTest test
Signed-off-by: snipe <snipe@snipe.net>
2025-05-05 22:12:08 +01:00
snipe
c776e0e7e9 Merge pull request #16851 from grokability/fix-dockerhub-repo
Fix dockerhub repo we're pushing to, and arm build names
2025-05-05 22:03:58 +01:00
Jeremy Price
54d3193b6f run arm builds on arm 2025-05-05 22:55:38 +02:00
Marcus Moore
326657c709 contributors:generate 2025-05-05 13:30:49 -07:00
Marcus Moore
c72e86ea2e Update casing for contributor 2025-05-05 13:29:05 -07:00
Marcus Moore
34b1ca29d3 Remove duplicate contributor (QveenSi) 2025-05-05 13:28:25 -07:00
Marcus Moore
1dc876a436 docs: add @austinsasko as a contributor 2025-05-05 13:19:37 -07:00
Marcus Moore
b28bc2c500 docs: add @drexljo as a contributor 2025-05-05 13:18:53 -07:00
Marcus Moore
c38d98b00a docs: add @jfwiebe as a contributor 2025-05-05 13:18:29 -07:00
Marcus Moore
7b83df088b docs: add @JemCdo as a contributor 2025-05-05 13:18:29 -07:00
Marcus Moore
c8b1240665 docs: add @jjasghar as a contributor 2025-05-05 13:18:28 -07:00
Marcus Moore
8a9d6bbdca docs: add @pottom as a contributor 2025-05-05 13:18:27 -07:00
Marcus Moore
6859b36e7c docs: add @dasjoe as a contributor 2025-05-05 13:18:26 -07:00
Marcus Moore
f0073c1528 docs: add @gl-pup as a contributor 2025-05-05 13:18:26 -07:00
Marcus Moore
f6b7e621b7 docs: add @gastamper as a contributor 2025-05-05 13:18:25 -07:00
Marcus Moore
108a0179ca docs: add @LeafedFox as a contributor 2025-05-05 13:18:24 -07:00
Marcus Moore
2baf65aa62 docs: add @m4us1ne as a contributor 2025-05-05 13:18:24 -07:00
Marcus Moore
74c4e9665e docs: add @lopezio as a contributor 2025-05-05 13:18:23 -07:00
Marcus Moore
ae9c22f327 docs: add @loganswartz as a contributor 2025-05-05 13:18:22 -07:00
Marcus Moore
37bca6febd docs: add @sniff122 as a contributor 2025-05-05 13:18:22 -07:00
Marcus Moore
30196793bd docs: add @KorvinSzanto as a contributor 2025-05-05 13:18:21 -07:00
Marcus Moore
3060282ffb docs: add @juhotaipale as a contributor 2025-05-05 13:18:20 -07:00
Marcus Moore
d63bba8db7 docs: add @juanfont as a contributor 2025-05-05 13:18:20 -07:00
Marcus Moore
2c12ee01a0 docs: add @CalvinSchwartz as a contributor 2025-05-05 13:18:19 -07:00
Marcus Moore
aa76424a74 docs: add @byronwolfman as a contributor 2025-05-05 13:18:18 -07:00
Marcus Moore
9188d6229e docs: add @benperiton as a contributor 2025-05-05 13:18:18 -07:00
Marcus Moore
5555f32ffe docs: add @arukompas as a contributor 2025-05-05 13:18:17 -07:00
Marcus Moore
59062980ff docs: add @hex128 as a contributor 2025-05-05 13:18:16 -07:00
Marcus Moore
f4aac5f0b7 docs: add @disc as a contributor 2025-05-05 13:18:16 -07:00
Marcus Moore
5c167aa2a9 docs: add @AlexanderWPapyrus as a contributor 2025-05-05 13:18:15 -07:00
Marcus Moore
8e1eed498e docs: add @MelonSmasher as a contributor 2025-05-05 13:18:14 -07:00
Marcus Moore
e449f39ea6 docs: add @fabiang as a contributor 2025-05-05 13:16:43 -07:00
Marcus Moore
97171e0e1c docs: add @Jarli01 as a contributor 2025-05-05 13:16:42 -07:00
Marcus Moore
5935ca4664 docs: add @dkmansion as a contributor 2025-05-05 13:16:42 -07:00
Marcus Moore
21c88cd311 docs: add @splashx as a contributor 2025-05-05 13:16:41 -07:00
Marcus Moore
5c786d8b70 docs: add @corydlamb as a contributor 2025-05-05 13:09:28 -07:00
Marcus Moore
d718d210ed docs: add @bricelabelle as a contributor 2025-05-05 13:09:27 -07:00
Marcus Moore
f50c5d22b8 docs: add @bmkalle as a contributor 2025-05-05 13:09:27 -07:00
Marcus Moore
c36f9a432e docs: add @terwey as a contributor 2025-05-05 13:09:26 -07:00
Marcus Moore
65b6b02b1d docs: add @xWyatt as a contributor 2025-05-05 12:54:08 -07:00
Marcus Moore
9c65d7c057 docs: add @Wouter0100 as a contributor 2025-05-05 12:54:08 -07:00
Marcus Moore
eab07834cf docs: add @valentyntu as a contributor 2025-05-05 12:54:07 -07:00
Marcus Moore
eb38f33baf docs: add @viclou as a contributor 2025-05-05 12:54:06 -07:00
Marcus Moore
462f9f2f39 docs: add @yannikp as a contributor 2025-05-05 12:54:05 -07:00
Marcus Moore
1021ccb230 docs: add @timwsuqld as a contributor 2025-05-05 12:54:05 -07:00
Marcus Moore
84e9a3a7d6 docs: add @p3nj as a contributor 2025-05-05 12:54:04 -07:00
Marcus Moore
c0060b3625 docs: add @sreyemnayr as a contributor 2025-05-05 12:54:03 -07:00
Marcus Moore
197aa12c61 docs: add @octobunny as a contributor 2025-05-05 12:54:02 -07:00
Marcus Moore
dfb2959751 docs: add @nixn as a contributor 2025-05-05 12:54:01 -07:00
Marcus Moore
95fb4f0e45 docs: add @rcmcdonald91 as a contributor 2025-05-05 12:54:00 -07:00
Marcus Moore
b2c729b7b8 docs: add @owalerys as a contributor 2025-05-05 12:53:59 -07:00
Marcus Moore
fe9b224a44 docs: add @nunomaduro as a contributor 2025-05-05 12:53:59 -07:00
Marcus Moore
fc4e8c68f2 docs: add @Scorcher as a contributor 2025-05-05 12:53:58 -07:00
Marcus Moore
6fb1c03908 docs: add @nticaric as a contributor 2025-05-05 12:53:57 -07:00
Marcus Moore
96ccfdb8cc docs: add @firefrei as a contributor 2025-05-05 12:53:57 -07:00
Marcus Moore
75fd07e057 docs: add @mzack5020 as a contributor 2025-05-05 12:53:56 -07:00
Marcus Moore
87fe69ecfb docs: add @Mateus-Romera as a contributor 2025-05-05 12:53:55 -07:00
Marcus Moore
19b47030ca docs: add @Nevets82 as a contributor 2025-05-05 12:53:54 -07:00
Marcus Moore
cf4e3fcc37 docs: add @snazy2000 as a contributor 2025-05-05 12:53:54 -07:00
Marcus Moore
bef4133f51 docs: add @smcpeck as a contributor 2025-05-05 12:53:53 -07:00
Marcus Moore
7ac24efced docs: add @cendai-mis as a contributor 2025-05-05 12:53:52 -07:00
Marcus Moore
d8d4a7075e docs: add @Shankschn as a contributor 2025-05-05 12:53:51 -07:00
Marcus Moore
dd4c9df6d1 docs: add @serkanerip as a contributor 2025-05-05 12:53:50 -07:00
Marcus Moore
da28c02b50 docs: add @SBrown2021 as a contributor 2025-05-05 12:53:50 -07:00
Marcus Moore
54858402e3 docs: add @McG800 as a contributor 2025-05-05 12:53:49 -07:00
Marcus Moore
b39d8cc0b9 docs: add @rosscdh as a contributor 2025-05-05 12:53:48 -07:00
Marcus Moore
4c7c33800a docs: add @rickheil as a contributor 2025-05-05 12:53:47 -07:00
Marcus Moore
d2c604a7ce docs: add @Nothing4You as a contributor 2025-05-05 12:53:47 -07:00
Marcus Moore
91243fb6c0 docs: add @mbrrg as a contributor 2025-05-05 12:53:46 -07:00
Marcus Moore
940a85888a docs: add @deloz as a contributor 2025-05-05 12:53:45 -07:00
Marcus Moore
280c12e22b docs: add @Galaxy102 as a contributor 2025-05-05 12:53:44 -07:00
Marcus Moore
39e644d048 docs: add @manu-crealytics as a contributor 2025-05-05 12:53:44 -07:00
Marcus Moore
9acb3e5935 docs: add @marcquark as a contributor 2025-05-05 12:53:43 -07:00
Marcus Moore
8ac5b5df61 docs: add @brandon-bailey as a contributor 2025-05-05 12:53:42 -07:00
Marcus Moore
434932599c docs: add @thinkl33t as a contributor 2025-05-05 12:53:42 -07:00
Marcus Moore
81b8c445c6 docs: add @vicleos as a contributor 2025-05-05 12:53:41 -07:00
Marcus Moore
002bb72a8d docs: add @herroworrd as a contributor 2025-05-05 12:53:40 -07:00
Marcus Moore
288770900e docs: add @robintemme as a contributor 2025-05-05 12:53:39 -07:00
Marcus Moore
f6f6a23f8b docs: add @wewhite as a contributor 2025-05-05 12:53:39 -07:00
Marcus Moore
522fa7be44 docs: add @Serdnad as a contributor 2025-05-05 12:53:38 -07:00
Marcus Moore
272d9e0552 docs: add @mink-adao-duy as a contributor 2025-05-05 12:53:37 -07:00
Marcus Moore
9060a3cc13 docs: add @ahpaleus as a contributor 2025-05-05 12:53:36 -07:00
Marcus Moore
b6a9c0e68b docs: add @DanielRuf as a contributor 2025-05-05 12:53:36 -07:00
Marcus Moore
b43ae5be13 docs: add @dkaatz as a contributor 2025-05-05 12:53:35 -07:00
Marcus Moore
6384041107 docs: add @seanborg-codethink as a contributor 2025-05-05 12:53:34 -07:00
Marcus Moore
89703cd9df docs: add @sorvani as a contributor 2025-05-05 12:53:33 -07:00
Marcus Moore
f6aa9f1318 docs: add @fe80 as a contributor 2025-05-05 12:53:33 -07:00
Marcus Moore
838e214b24 docs: add @phil-flip as a contributor 2025-05-05 12:53:32 -07:00
Marcus Moore
628c444cd4 docs: add @aranar-pro as a contributor 2025-05-05 12:53:31 -07:00
Marcus Moore
e8289b0f45 docs: add @JonathonReinhart as a contributor 2025-05-05 12:53:31 -07:00
Marcus Moore
86816f632f docs: add @test1337ahp as a contributor 2025-05-05 12:53:30 -07:00
Marcus Moore
494710306b docs: add @NebelKreis as a contributor 2025-05-05 12:53:29 -07:00
Marcus Moore
7a5fe4981f docs: add @mnemonicly as a contributor 2025-05-05 12:53:29 -07:00
snipe
a67b320cae Merge pull request #15907 from uberbrady/protect_assigned_to_assigned_type_rebased
Rebased version of #15629 - prevent setting assigned_to without setting assigned_type
2025-05-05 20:42:46 +01:00
snipe
9ef20997a5 Merge pull request #16861 from uberbrady/cherry_pick_avery_3490
adds support for Avery 3490 (Cherry-picked from 'master')
2025-05-05 15:01:00 +01:00
Calvin Schwartz
cfd10ae294 adds support for Avery 3490 2025-05-05 14:59:10 +01:00
snipe
9b85e9a071 Add @realchrisolin as a contributor 2025-05-05 14:44:04 +01:00
Godfrey M
0eb3f6b952 set max to 5 2025-05-05 14:42:06 +01:00
Godfrey M
68b0f80fce fix input max, and help block position 2025-05-05 14:42:06 +01:00
Godfrey M
93489529a3 adds Field offset option to labels 2025-05-05 14:42:06 +01:00
snipe
511be74e74 Add @chfsx as a contributor 2025-05-05 14:42:06 +01:00
Fabian Schmid
bdee067803 [FIX] set upload-limit 2025-05-05 14:42:06 +01:00
snipe
32156cace3 Merge pull request #16847 from realchrisolin/issue16214
add barcode support for Avery 3490
2025-05-05 14:40:54 +01:00
snipe
407962d998 Merge pull request #16790 from Godmartinz/empty_field_columns_labels
Adds Label fields offset as an option
2025-05-05 14:09:40 +01:00
snipe
1245289906 Add @chfsx as a contributor 2025-05-05 14:08:31 +01:00
snipe
76c19202ed Merge pull request #16806 from chfsx/patch-1
[FIX] set upload-limit
2025-05-05 14:07:42 +01:00
snipe
30688114be Merge remote-tracking branch 'origin/develop' 2025-05-05 14:04:52 +01:00
snipe
ada8195e2e Merge pull request #16860 from grokability/better_location_scope_check
Livewire component for smoother check for location companies
2025-05-05 14:04:23 +01:00
snipe
83d6e9ad8a Removed log error
Signed-off-by: snipe <snipe@snipe.net>
2025-05-05 14:00:05 +01:00
snipe
4469db0bd3 Livewire component for smoother check for location companies
Signed-off-by: snipe <snipe@snipe.net>
2025-05-05 13:55:28 +01:00
snipe
34088bcc17 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-05-05 11:17:01 +01:00
snipe
5e2dba5483 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-05-05 11:15:46 +01:00
Fabian Schmid
9de97694c3 [FIX] set upload-limit 2025-05-05 08:35:45 +02:00
Jeremy Price
8349065b0a stop buiulding intel on arm 2025-05-02 10:59:42 +02:00
Jeremy Price
bb82b2513e Fix dockerhub repo we're pushing to, and arm build names 2025-05-02 10:58:25 +02:00
Calvin Schwartz
07835766cc adds support for Avery 3490 2025-05-01 21:11:42 -04:00
snipe
e781c170f3 Merge pull request #16841 from Godmartinz/dark_mode_black_input_group_add_on_color_fix
remove duplicate input-group color corrections from theme skins
2025-05-01 01:48:49 +01:00
Godfrey M
43dfbd3d21 remove duplicate input-group color correction from other themes 2025-04-30 16:21:15 -07:00
Godfrey M
073c9f5f7c remove duplicate input-group color correction 2025-04-30 16:16:14 -07:00
snipe
f9d67dd431 Merge pull request #16840 from uberbrady/docker_backmerge
Copy changes from 'master' to develop for docker builds
2025-04-30 21:19:22 +01:00
Brady Wetherington
a2ea4c7fd0 Copy changes from 'master' to develop for docker builds 2025-04-30 21:12:10 +01:00
Brady Wetherington
251851ec6a Try to get Docker images to build for both architectures 2025-04-30 18:00:39 +01:00
snipe
049a669186 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:46:16 +01:00
snipe
a0358e32d7 Removed escaping
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 16:46:06 +01:00
snipe
d29f13bae9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:26:38 +01:00
snipe
c2023c5c56 Ampersand showing in Custom fields [sc-29051]
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 16:25:44 +01:00
snipe
c758355df9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:14:34 +01:00
snipe
43c310c82d Merge pull request #16531 from akemidx/bug/sc-28715
FIXED: Purchase Cost Column Always Shown
2025-04-30 15:54:31 +01:00
snipe
79d97a83af Merge remote-tracking branch 'origin/develop' 2025-04-30 15:48:38 +01:00
snipe
939a0c44dc Merge pull request #16826 from Godmartinz/fix_multiple_inline_label_field_options
Reworked fix for for 24mm_D label indent errror
2025-04-30 15:47:57 +01:00
snipe
85bd47c240 Merge remote-tracking branch 'origin/develop' 2025-04-30 15:35:10 +01:00
snipe
2b9cf1663b Merge pull request #16837 from grokability/fmcs_scoping_improvements
Small improvements to scoped views
2025-04-30 15:33:53 +01:00
snipe
0a29e90701 Smal improvements to scoping displays
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 15:24:42 +01:00
snipe
d1be13e7d4 Added button text to translations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:32:29 +01:00
snipe
049a777ca8 Added buttons to dashboard
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:32:20 +01:00
snipe
0dcaa83a3e Nicer breadcrumb
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:22:13 +01:00
snipe
db706269e6 Fixed validation message
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:22:06 +01:00
snipe
473ead9616 Merge remote-tracking branch 'origin/develop' 2025-04-30 13:57:27 +01:00
snipe
4f72505dc3 Merge pull request #16836 from grokability/fixes/#16834_handle_bad_data_in_permissions
Fixed #16834 - better handle bad data in permissions
2025-04-30 13:56:59 +01:00
snipe
340f8b73a5 Updated comments
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 13:56:37 +01:00
snipe
6c6b37000a Better handle permissions with bad data
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 13:43:05 +01:00
snipe
b5c79624c6 Display notes in group listing
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 11:14:42 +01:00
snipe
cf2850933c Merge remote-tracking branch 'origin/develop' 2025-04-30 10:19:43 +01:00
snipe
49d66dedf4 Nicer existing image display
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 10:19:12 +01:00
snipe
ff2564c57a Merge remote-tracking branch 'origin/develop' 2025-04-30 10:12:05 +01:00
snipe
ebbcdbc864 Nicer breadcrumb
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 10:11:55 +01:00
snipe
a18691c09f Set image path in singleton
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 10:11:48 +01:00
snipe
245b0b0f8f Added image path
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 10:11:40 +01:00
snipe
1d3b0478f9 Merge pull request #16829 from marcusmoore/fixes/contributors-fix
Fixed updating CONTRIBUTORS.md via cli
2025-04-30 01:23:59 +01:00
Marcus Moore
a5d0307532 Wrap username in quotes 2025-04-29 16:20:00 -07:00
snipe
91d3848246 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-04-29 23:17:51 +01:00
snipe
7daecdd53f Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 23:17:03 +01:00
snipe
667b4a49c3 Merge pull request #16828 from grokability/chore/sc-29037
Add audit button to BS table partial, redirect if asset won't validate
2025-04-29 23:07:45 +01:00
snipe
2518e60a5e Corrected gates
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 22:59:05 +01:00
snipe
9ff8b62cee Updated icon
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 22:58:58 +01:00
snipe
5086c80658 Invoke a validator, redirect to edit screen if invalid
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 22:47:34 +01:00
snipe
cb852fc20f Added audit gate to API
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 22:47:12 +01:00
snipe
fb3b34e0f6 Add audit button to BS table partial
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 22:47:02 +01:00
snipe
c031f0b45e Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	public/css/dist/skins/skin-blue-dark.css
#	public/css/dist/skins/skin-blue-dark.min.css
#	public/css/dist/skins/skin-green-dark.css
#	public/css/dist/skins/skin-green-dark.min.css
#	public/css/dist/skins/skin-orange-dark.css
#	public/css/dist/skins/skin-orange-dark.min.css
#	public/css/dist/skins/skin-purple-dark.css
#	public/css/dist/skins/skin-purple-dark.min.css
#	public/css/dist/skins/skin-red-dark.css
#	public/css/dist/skins/skin-red-dark.min.css
#	public/css/dist/skins/skin-yellow-dark.css
#	public/css/dist/skins/skin-yellow-dark.min.css
#	public/mix-manifest.json
2025-04-29 20:38:41 +01:00
snipe
8d4fc07f63 Updated dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 20:37:47 +01:00
snipe
a0514ad8c1 Merge pull request #16799 from marcusmoore/bug/sc-28990
Handle category being null in CheckoutableListener
2025-04-29 20:37:11 +01:00
snipe
4e03e525a4 Merge pull request #16797 from Godmartinz/dark_mode_green_fix
Fixed Dark Mode color choices for fieldset links
2025-04-29 20:35:59 +01:00
snipe
0efdebcfd8 Merge pull request #16827 from grokability/fixed_custom_field_fieldset_display
Fixed fieldset display if custom fields are not available
2025-04-29 20:26:14 +01:00
snipe
c7835d2d1d Fixed copypasta
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 20:08:34 +01:00
snipe
3e3bc0a347 Removed test tab
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 20:01:22 +01:00
snipe
184a22828f Use input vs get
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 19:22:10 +01:00
snipe
f26e27d23e Display in checkboxes not saving on custom [sc-29028]
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 19:21:50 +01:00
snipe
e717f1e780 Removed logging
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 19:21:18 +01:00
snipe
d1085a0f46 Move notes above custom fields
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 18:53:31 +01:00
Godfrey M
2e0913bb3b remove unused method 2025-04-29 10:49:19 -07:00
Godfrey M
851ae46ea9 reworked fix for for 24mm_D label indent errior 2025-04-29 10:45:29 -07:00
snipe
89a52b7551 Fixed fieldset display if custom fields are not available
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 18:09:32 +01:00
snipe
fdbb9568ae Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-29 12:39:31 +01:00
snipe
15870d0e75 Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 12:38:07 +01:00
snipe
eb2c536221 Updated translations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 12:36:55 +01:00
snipe
bced7df539 Merge pull request #16822 from grokability/nicer_optional_disclosures
Nicer disclosure UI for optional data
2025-04-29 12:31:14 +01:00
snipe
fe672ed727 Nicer disclosure UI for optional data
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 12:10:09 +01:00
snipe
d817883459 Merge remote-tracking branch 'origin/develop' 2025-04-29 10:25:42 +01:00
snipe
6e60594e66 Fixed escaped text
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 10:25:20 +01:00
snipe
12255979ac Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-29 10:22:21 +01:00
snipe
f357dd690b Updated dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 10:21:24 +01:00
snipe
255e0c3bdc Merge pull request #16602 from akemidx/bug/sc-25897-2
FIXED: Text Overflow on Settings Tiles
2025-04-29 10:20:45 +01:00
snipe
8984d60c39 Merge pull request #16798 from grokability/more-mint-support-and-newer-ubuntus
Support more Mint versions and verify newer Ubuntu versions in snipeit.sh
2025-04-29 10:19:28 +01:00
snipe
6dbfc8875b Merge pull request #16817 from marcusmoore/fixes/restore-custom-field-values-on-asset-edit-v2
Maintain checkbox and radio custom field values on asset edit page
2025-04-29 10:17:10 +01:00
snipe
139f45872c Merge pull request #16819 from marcusmoore/chore/migrate-radio-helpers
Replaced calls to Form::radio helper on user create and edit pages
2025-04-29 10:16:16 +01:00
snipe
eb223a4c09 Merge pull request #16821 from grokability/small_settings_ui_fixes
Use default BS tables “no results” view, small UI formatting improvements
2025-04-29 10:15:16 +01:00
snipe
c3531e9eba Nicer formatting on smaller screens
Signed-off-by: snipe <snipe@snipe.net>
2025-04-29 10:11:00 +01:00
Marcus Moore
db3f8e5d68 Replace a Form::radio on user edit page 2025-04-28 15:08:05 -07:00
Marcus Moore
8ca11542f8 Replace a Form::radio on user edit page 2025-04-28 15:03:54 -07:00
Marcus Moore
36be23f7e4 Replace a Form::radio on user edit page 2025-04-28 14:57:03 -07:00
Marcus Moore
51f67082f4 Replace a Form::radio on user edit page 2025-04-28 14:23:39 -07:00
Marcus Moore
ea2f0cdd7b Replace a Form::radio on user edit page 2025-04-28 14:18:01 -07:00
Marcus Moore
97d2e6f9d4 Replace a Form::radio on user edit page 2025-04-28 14:03:27 -07:00
Marcus Moore
28ea75512c Replace from Form::radio on user edit page 2025-04-28 13:47:23 -07:00
snipe
9b6683ae16 Merge pull request #16818 from Godmartinz/fix_multiple_inline_label_field_options
Fixed label fields multiple option alignment bug
2025-04-28 21:37:19 +01:00
Godfrey M
149d276e06 fix field alignment issue 2025-04-28 13:26:49 -07:00
snipe
a519ebe19b Default BS table no results
Signed-off-by: snipe <snipe@snipe.net>
2025-04-28 09:59:52 +01:00
snipe
66b537bc64 Fixed duplicate ID
Signed-off-by: snipe <snipe@snipe.net>
2025-04-28 09:59:28 +01:00
snipe
9722d29070 Use default BS tables “no results” view
Signed-off-by: snipe <snipe@snipe.net>
2025-04-28 09:59:17 +01:00
snipe
366b61850b Merge remote-tracking branch 'origin/develop' 2025-04-26 17:54:02 +01:00
snipe
c748278637 Merge pull request #16810 from grokability/settings_improvements_branding
Use fieldsets for branding page
2025-04-26 17:53:11 +01:00
snipe
23c39520e5 Added empty alt tags to images since we don’t have additional info
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:42:49 +01:00
snipe
41f68d8a30 Use locked x-icon
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:33:18 +01:00
snipe
7320e823ad Added alt text for sad panda
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:33:09 +01:00
snipe
1aeda546fd Added urls for pa11y
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:33:00 +01:00
snipe
91fcff5faf Added translations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:32:52 +01:00
snipe
d97e54f85e Use fieldsets for branding page
Signed-off-by: snipe <snipe@snipe.net>
2025-04-26 17:32:41 +01:00
snipe
4b58af8850 Fixed message while processing audit on quickscan
Signed-off-by: snipe <snipe@snipe.net>
2025-04-24 14:25:42 +01:00
snipe
89be6bd183 Merge remote-tracking branch 'origin/develop' 2025-04-24 14:06:00 +01:00
snipe
0822aa985d Fixed #16802 - use asset endpoint for assets assigned to locations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-24 14:05:44 +01:00
snipe
e120331a2c Merge remote-tracking branch 'origin/develop' 2025-04-24 12:16:53 +01:00
snipe
e5c6e294ec Added #16239 - make city searchabke in users
Signed-off-by: snipe <snipe@snipe.net>
2025-04-24 12:16:41 +01:00
Marcus Moore
25fdde1807 Handle null category 2025-04-23 14:16:28 -07:00
snipe
cb8a212d96 Merge remote-tracking branch 'origin/develop' 2025-04-23 21:57:20 +01:00
snipe
fa45ca1453 Stupid fix for when people use id instead of an actual ID
@todo - use RMB for these

Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:56:43 +01:00
Jeremy Price
67ec042ee3 Support more Mint versions and verify newer Ubuntu versions in snipeit.sh
In https://github.com/grokability/snipe-it/pull/16763 we added support
for Linux Mint 22.1, which is the newest stable version of Mint, but but
didn't get around to testing or adding support for less-recent versions.

With this PR, we're adding support for the following LinuxMint versions
* 22
* 21.3
* 21.2
* 21.1
* 21

We recommend using the newest version, but at least now you won't be
blocked so long as you're remotely up-to-date.

We're not going back any further because prior versions are based on
Ubuntu 20.04 (Focal), which is out of support as of April 2025, aka this
month.

Additionally, the most recent Ubuntu version specifically mentioned in
the script is 23.10. The script in its current version works all the way
up to the most recent version, so we're adding notation to that
effect.

Newly included Ubuntu versions are
25.04
24.10
24.04 (LTS)
2025-04-23 13:37:33 -07:00
snipe
7aec431ac5 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:30:16 +01:00
snipe
8b6c88a7c6 Okay…
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:27:28 +01:00
snipe
9f8fddb4c5 Removed accidentally commited generated images
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:23:58 +01:00
snipe
8fcf7e3b9d Merge pull request #16792 from grokability/add_pa11y
Added pa11y
2025-04-23 21:17:35 +01:00
snipe
d9326fc555 Removed sky-is-blue text
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:13:40 +01:00
snipe
c1196599e1 Merge branch 'develop' into add_pa11y 2025-04-23 21:11:59 +01:00
snipe
d19681dea1 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 21:05:38 +01:00
Godfrey M
a26279e0b9 adds custom field link color correction to all dark modes 2025-04-23 12:38:58 -07:00
Marcus Moore
29433882ea Restore custom field checkbox and radio button values when switching model 2025-04-23 12:38:09 -07:00
snipe
e3f511ec7c Small accessibility improvements
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 15:53:41 +01:00
snipe
f0b18042f9 Added aria label to admin settings search
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 14:01:52 +01:00
snipe
75c9936dbb Added alt text
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 12:37:13 +01:00
snipe
ddd4065c81 Merge pull request #16793 from spencerrlongg/bug/sc-28972
Added Nullsafe Checks to Users
2025-04-23 12:01:25 +01:00
snipe
ad88a72d0a Override legend style
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 06:31:25 +01:00
snipe
6a00620552 More urls
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 06:27:20 +01:00
snipe
a9db8d6898 Added more urls
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 06:20:23 +01:00
snipe
65cc1bbd7e Ignore screenshots
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 05:53:11 +01:00
spencerrlongg
2935697209 added nullsafe checks to user 2025-04-22 23:39:24 -05:00
snipe
3ae2454228 This doesn’t work the way I thought
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 05:35:49 +01:00
snipe
11b48ee636 Removed dupes
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 05:21:32 +01:00
snipe
2aa864afaa Updated rules
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 05:16:22 +01:00
snipe
ec65e64a67 Updated ignore rules
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 05:06:34 +01:00
snipe
7e01d23aa2 Renamed file
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 04:50:14 +01:00
snipe
f05b2ad9be First stabs at improvements
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 04:48:47 +01:00
snipe
eaaac76435 Added configs
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 04:48:39 +01:00
snipe
41160c64a8 Merge pull request #16791 from grokability/location_company_scoping_improvements
Improved settings page for location-company scoping
2025-04-23 01:25:54 +01:00
snipe
0cfef59568 Updated string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 01:22:25 +01:00
snipe
d953d1a889 Use translation strings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 01:21:54 +01:00
snipe
4aa06f6a75 Update dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-23 00:30:06 +01:00
snipe
07a9bded95 Added strings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 23:50:28 +01:00
snipe
f686e86afb Refactored setting page
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 23:50:21 +01:00
snipe
9f28dae01b Invoke the artisan command
This *might* suck for people with a lot of assets, etc

Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 23:50:11 +01:00
snipe
67ab584dc7 Updated text
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 23:49:31 +01:00
Godfrey M
5da492cbf5 set max to 5 2025-04-22 12:07:02 -07:00
Godfrey M
d871c529d1 fix input max, and help block position 2025-04-22 11:59:19 -07:00
Godfrey M
7c2c5ea98d adds Field offset option to labels 2025-04-22 10:50:20 -07:00
snipe
bf2299daf8 Merge remote-tracking branch 'origin/develop' 2025-04-22 17:51:48 +01:00
snipe
2e31a0530f Merge pull request #16789 from grokability/fixes/#16475_delete_oauth_clients
Fixed #16475 - Allow deleting oauth client
2025-04-22 17:48:24 +01:00
snipe
5f66fb0bba Allow deleting oauth user
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 17:42:07 +01:00
snipe
164930d0dd Merge remote-tracking branch 'origin/develop' 2025-04-22 16:35:23 +01:00
snipe
143e9cdd61 Merge pull request #16788 from grokability/better_handle_arrays_for_model_ids
Better handle model_id arrays passed to the API
2025-04-22 16:33:47 +01:00
snipe
aed32e6ada Better handle arrays in API rerquests for model_id
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 16:23:34 +01:00
snipe
ed86c90b7e Merge pull request #16787 from uberbrady/suppress_action_date_error_in_loggable
Fixed: [RB-19645] Suppress error message about 'action_date' not existing
2025-04-22 14:48:38 +01:00
snipe
387dbac809 Merge remote-tracking branch 'origin/develop' 2025-04-22 14:36:14 +01:00
snipe
7dc606fd3b Merge pull request #16786 from grokability/populate_manufacturers
Added ability to seed common manufacturers
2025-04-22 14:35:20 +01:00
snipe
185fd559c9 Added test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 14:34:03 +01:00
snipe
473c684fa5 Nicer translation
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 14:22:58 +01:00
Brady Wetherington
d3dbd82ce2 Check that array key exists before accessing it 2025-04-22 14:20:01 +01:00
snipe
e5dc13e48c Added ability to seed manufacturers
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 14:13:46 +01:00
snipe
3b661e5a99 Merge remote-tracking branch 'origin/develop' 2025-04-22 12:39:35 +01:00
snipe
2a2d118973 Updated readme with star count
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 12:38:05 +01:00
snipe
90c1c0e655 Merge remote-tracking branch 'origin/develop' 2025-04-22 11:42:49 +01:00
snipe
f2f17402c9 Merge pull request #16785 from grokability/feature/sc-28956
Added checkout date to license seats
2025-04-22 11:41:52 +01:00
snipe
39f764803d Added checkout date to license seats
Signed-off-by: snipe <snipe@snipe.net>
2025-04-22 11:38:54 +01:00
snipe
55176816aa Merge pull request #16784 from marcusmoore/fix-flaky-timestamp-tests
Fixed flaky test
2025-04-22 11:03:58 +01:00
Marcus Moore
1f7d4e0793 Fix flaky test 2025-04-21 15:14:53 -07:00
snipe
e17fae02ad Merge pull request #16783 from uberbrady/upgrade_debugbar
Upgrade Debugbar to make deprecation warnings easier to find
2025-04-21 21:44:28 +01:00
Brady Wetherington
3c1099a6a9 Upgrade Debugbar to make deprecation warnings easier to find 2025-04-21 21:00:02 +01:00
snipe
21d8e7695b Merge remote-tracking branch 'origin/develop' 2025-04-21 20:19:54 +01:00
snipe
b1761ec246 Merge pull request #16781 from uberbrady/make_min_qty_not_required
min_amt wasn't correctly being set to required or not
2025-04-21 18:44:20 +01:00
Brady Wetherington
03f0f13727 min_amt wasn't correctly being set to required or not 2025-04-21 18:32:53 +01:00
snipe
12648912aa Added test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 16:45:10 +01:00
snipe
4c898a8741 Fixed filename
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 16:44:47 +01:00
snipe
1acc452cfe Merge remote-tracking branch 'origin/develop' 2025-04-21 14:59:26 +01:00
snipe
6bef8620e4 Merge pull request #16780 from grokability/feature/sc-23604
Fixed #9249 - added file uploads to locations
2025-04-21 14:49:02 +01:00
snipe
beb5560dce Added files tab
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 14:43:04 +01:00
snipe
2ebe1ebc69 Load location route files
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 14:42:58 +01:00
snipe
00092a079f Added uploads method
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 14:42:10 +01:00
snipe
9d313eb2d9 Added locations dir
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 14:42:02 +01:00
snipe
e8404c8720 Moved location routes
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 14:41:52 +01:00
snipe
1375e1feee Merge remote-tracking branch 'origin/develop' 2025-04-21 12:21:08 +01:00
snipe
e71e25955a Check for array
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 12:20:03 +01:00
snipe
fa9ac3c449 Return value as int
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 11:53:26 +01:00
snipe
70854b2c42 Small fix or groups API
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 11:49:49 +01:00
snipe
e2a1be9762 Int values for group permissions on API
Signed-off-by: snipe <snipe@snipe.net>
2025-04-21 10:49:28 +01:00
snipe
2187adf59a Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 15:34:58 +01:00
snipe
f2c2fefd99 Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 15:28:48 +01:00
snipe
b5a960e933 Updated translations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 15:27:41 +01:00
snipe
66b2cc2e28 Set empty array if permissions are null
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 15:17:55 +01:00
snipe
47246a3fdf Merge pull request #15420 from grokability/return_boolean_in_api
Possible fix for #15315 - decode as permissions as boolean
2025-04-19 15:01:36 +01:00
snipe
4d01b2bb4f Removed invalid json_decode() flag
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 14:57:43 +01:00
snipe
876715b3c5 Merge pull request #16435 from marcusmoore/fixes/prevent-deleting-accessories-with-checkouts
Disallow deleting accessories that have active checkouts
2025-04-19 14:38:14 +01:00
snipe
93d74587e1 Merge pull request #16538 from marcusmoore/bug/sc-28305
Return null from accessory transformer for missing assignment
2025-04-19 14:37:45 +01:00
snipe
5bae74bc1b Merge pull request #16688 from 36864/patch-1
Fixes #14734: Only show signatures for the printed user
2025-04-19 14:36:26 +01:00
snipe
0259c91a06 Added @mrdahbi as a contributor
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 14:34:15 +01:00
snipe
04ccfc3002 Fixed: escape '/' in preg_quote of asset tag prefix (Applied #16542 to develop)
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 14:32:21 +01:00
snipe
495b7db72b Merge branch 'chore/sc-28495' into develop
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 14:29:30 +01:00
snipe
6e5eb55b45 Updated dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-19 14:28:01 +01:00
snipe
9ad99c1d81 Merge pull request #16494 from marcusmoore/bug/sc-28675
Avoid logging consumable checkins and purge action log of bad entries
2025-04-19 14:24:52 +01:00
snipe
622626bb27 Merge pull request #16521 from grokability/add-disable-saml-command
Add console command to disable SAML logins
2025-04-19 14:23:49 +01:00
snipe
f66575393a Merge pull request #16766 from CloCkWeRX/fix-placeholder-translations
Fixed: Admin > General Settings - Some placeholders not translatable
2025-04-18 16:40:53 +01:00
snipe
f67548cd70 Merge pull request #16738 from CloCkWeRX/patch-9
Fixed: Update SECURITY.md to indicate v8 is supported
2025-04-18 16:33:18 +01:00
snipe
cd63657a92 Merge pull request #16694 from r-xyz/api-files-notes
Fixed #16689: re-add `note` field in API files listing for AssetModel
2025-04-18 14:06:30 +01:00
snipe
0dcb315d9d Merge remote-tracking branch 'origin/develop' 2025-04-18 00:56:26 +01:00
snipe
54f2b62294 Fixed consumable item_no import field
Signed-off-by: snipe <snipe@snipe.net>
2025-04-18 00:55:56 +01:00
snipe
327ccbd0c9 Merge remote-tracking branch 'origin/develop' 2025-04-18 00:37:11 +01:00
snipe
1a1120220c Merge pull request #16765 from grokability/#15035-add-company_name_to_slack
Fixed #15035 - adds company to slack message
2025-04-18 00:36:25 +01:00
Daniel O'Connor
82d93b6980 Point to existing translation 2025-04-17 23:32:11 +00:00
Daniel O'Connor
72b2b2d819 Refactor to translatable placeholder text 2025-04-17 23:30:08 +00:00
snipe
ad6352adc4 Fixed #15035 - adds company to slack message
Signed-off-by: snipe <snipe@snipe.net>
2025-04-18 00:28:37 +01:00
snipe
f571d400e6 Merge remote-tracking branch 'origin/develop' 2025-04-17 23:29:12 +01:00
snipe
4170397094 Merge pull request #16731 from CloCkWeRX/patch-4
Fixed: Editing > Email input > Utilise HTML5 controls
2025-04-17 23:16:23 +01:00
snipe
1e15aca809 Merge pull request #16733 from CloCkWeRX/patch-6
Fixed: Suppliers > Edit > Mark URL inputs as HTML5 URL inputs
2025-04-17 23:15:53 +01:00
snipe
8234c3eb0f Merge pull request #16734 from CloCkWeRX/patch-7
Fixed: Users > Edit > Mark website as a URL field
2025-04-17 23:14:59 +01:00
snipe
80eea7b064 Merge pull request #16757 from CloCkWeRX/fields
Fixed: Admin > Custom Fields > Ensure name field is marked required
2025-04-17 23:14:26 +01:00
snipe
779c28661e Merge pull request #16753 from CloCkWeRX/admin-slack-hook
Fixed: Admin > Webhooks > Swap to url input
2025-04-17 23:13:58 +01:00
snipe
293aa52335 Merge remote-tracking branch 'origin/develop' 2025-04-17 23:13:04 +01:00
snipe
516f59f0fc Added @BeatSpark as contributor
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 23:12:51 +01:00
snipe
bfb55da1a3 Repeat #16571 without conflicts, correctly targeted
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 23:10:20 +01:00
snipe
79e2e5c272 Merge pull request #16729 from CloCkWeRX/patch-2
Fixed #16727: Bulk Audit > Mark Asset Tag input required
2025-04-17 23:06:26 +01:00
snipe
ca178ae9a7 Merge remote-tracking branch 'origin/develop' 2025-04-17 22:48:35 +01:00
snipe
db1af98992 Merge pull request #16764 from grokability/fixed_flaky_user_create_tests
Fixed flaky user creation tests
2025-04-17 22:46:42 +01:00
snipe
c8ea3ba79a Merge pull request #16763 from grokability/add-linux-mint
Fixed: #16715 - Added LinuxMint support to snipeit.sh
2025-04-17 22:40:33 +01:00
snipe
96d5e072fe Fixed flaky tests on user creation
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 22:39:04 +01:00
snipe
d25ba74123 Merge pull request #16762 from grokability/fixes/#15702-min_amt_and_termination_date_on_license_import
Fixed #15702 - Added termination_date, reordered fields for clarity
2025-04-17 21:37:27 +01:00
snipe
f05dce8960 Added min_amt explicitly
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 21:31:20 +01:00
snipe
0758e73c5f Added termination_date, reordered fields for clarity
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 21:29:27 +01:00
Jeremy Price
617ee026c0 Add LinuxMint support to snipeit.sh
Fixes: https://github.com/grokability/snipe-it/issues/16715

@synergy34 requested LinuxMint support in our installer script. Mint is
Ubuntu-based, so i figured this wouldn't be too big of an issue, and
indeed it wasn't.

It mostly involved just supporting the OS version strings, and removing
the ondrej ppa because 22.1 ships with php8.3 already.

We only support 22.1 for the moment, as that's the most recent version
and the only one I tested on.

If you're on 22/Wilma and want to try, change the 221 on line 579 to 22 and
give it a whirl... If 22/Wilma also has php8.3, then it will probably be
fine
2025-04-17 12:22:42 -07:00
Daniel O'Connor
0cec64c056 Update SECURITY.md to indicate v8 is support
Unsure if v7 still is
2025-04-17 16:02:31 +00:00
snipe
d0c810e418 Merge remote-tracking branch 'origin/develop' 2025-04-17 16:42:37 +01:00
snipe
915c730dae Fixed #16714 - moved custom validation out of array
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 16:42:25 +01:00
snipe
0451f1219a Merge pull request #16732 from CloCkWeRX/patch-5
Fixed: Manufacturers > Edit > Mark URL inputs as HTML5 url inputs
2025-04-17 16:27:03 +01:00
Daniel O'Connor
5290a95b6b Update resources/views/hardware/quickscan.blade.php 2025-04-18 00:53:37 +09:30
snipe
e407695ff9 Merge pull request #16741 from CloCkWeRX/patch-10
Fixed: Change Password > Mark password fields required for change password
2025-04-17 16:22:01 +01:00
snipe
c5b53b00c1 Merge pull request #16742 from CloCkWeRX/security-url
Fixed: Admin > Security - Mark url fields as URL type
2025-04-17 16:21:26 +01:00
snipe
d2ac9b9610 Added @CloCkWeRX as contributor
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 16:18:29 +01:00
snipe
537e695ae9 Merge pull request #16730 from CloCkWeRX/patch-3
Fixed: Depreciations > Create/Edit > Change controls to various number inputs
2025-04-17 16:15:24 +01:00
snipe
b4b158da9e Merge pull request #16747 from CloCkWeRX/admin-oauth-required
Fixed: Admin > OAuth > Mark fields required
2025-04-17 16:09:42 +01:00
snipe
ad072c0546 Moved validation email_array
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 16:04:56 +01:00
snipe
713e1671d4 Merge pull request #16749 from CloCkWeRX/admin-ldap-change-password-url
Fixed: Admin > LDAP > Use HTML5 inputs
2025-04-17 15:58:45 +01:00
snipe
087f9756a2 Merge pull request #16744 from CloCkWeRX/api-token-required
Fixed: Manage API Keys > New name field not marked required
2025-04-17 15:58:07 +01:00
snipe
eb0408703e Merge pull request #16725 from CloCkWeRX/patch-1
Fixed #16723: Mark category name as required in modals
2025-04-17 15:47:07 +01:00
Daniel O'Connor
7e961b690a Mark required 2025-04-17 11:05:03 +00:00
snipe
d496d2caeb Merge remote-tracking branch 'origin/develop' 2025-04-17 11:59:24 +01:00
snipe
81f3730d84 Merge pull request #16754 from grokability/fixes/ambiguous_clause_for_company_id
Fixed ambiguous clause using company_id
2025-04-17 11:58:15 +01:00
snipe
141fad8393 Fixed ambiguous clause using company_id
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 11:56:39 +01:00
Daniel O'Connor
58ff63845e Admin > Slack > Swap to url input 2025-04-17 10:47:37 +00:00
Daniel O'Connor
a8150b7864 Update resources/views/settings/ldap.blade.php 2025-04-17 19:57:52 +09:30
Daniel O'Connor
ce6724f788 Admin > LDAP > Swap to URL input 2025-04-17 10:25:23 +00:00
Daniel O'Connor
13faa8ab00 Admin > LDAP > Swap to URL input 2025-04-17 10:23:43 +00:00
Daniel O'Connor
89beb73836 Swap to URL input 2025-04-17 19:49:28 +09:30
Daniel O'Connor
8b7e36a697 Mark fields required 2025-04-17 10:17:32 +00:00
Daniel O'Connor
c0f3d89b0b Fixed: Manage API Keys > New name field not marked required 2025-04-17 10:00:26 +00:00
Daniel O'Connor
ec62a59e57 Update resources/views/depreciations/edit.blade.php 2025-04-17 19:20:44 +09:30
Daniel O'Connor
f9269cfc63 Mark required 2025-04-17 19:19:19 +09:30
Daniel O'Connor
56bc06746c Set max limit 2025-04-17 19:18:31 +09:30
Daniel O'Connor
497e94d8a0 Admin > Security - Mark url fields as URL type 2025-04-17 09:42:45 +00:00
Daniel O'Connor
aa77c8c528 Mark password fields required for change password 2025-04-17 09:40:27 +00:00
Daniel O'Connor
6cd2a5d1a5 Users > Edit > Mark website as a URL field 2025-04-17 09:35:35 +00:00
Daniel O'Connor
e4a3a1a35f Suppliers > Edit > Mark URL inputs as HTML5 URL inputs 2025-04-17 09:34:45 +00:00
Daniel O'Connor
06f3cc1345 Manufacturers > Edit > Opt into HTML fields 2025-04-17 09:33:24 +00:00
Daniel O'Connor
3a6832ea58 Editing > Email input > Utilise HTML5 controls
Should be safe as this is validated by the UI as a singular email.
2025-04-17 09:32:02 +00:00
Daniel O'Connor
d2bb7fc926 Deprecations > Create/Edit > Mark number of months as a numeric control 2025-04-17 09:30:56 +00:00
Daniel O'Connor
4b93f329c2 Bulk Audit > Mark Asset Tag input required
Fix https://github.com/grokability/snipe-it/issues/16727
2025-04-17 09:29:43 +00:00
Daniel O'Connor
f03da92152 Mark category name as required in modals
Fix #16723
2025-04-17 09:27:04 +00:00
snipe
e70b75c350 Merge remote-tracking branch 'origin/develop' 2025-04-17 01:00:34 +01:00
snipe
88acdbcc28 Move array return
Signed-off-by: snipe <snipe@snipe.net>
2025-04-17 01:00:09 +01:00
snipe
23623cca2c Merge pull request #16719 from grokability/fixes_weird_layout_datepicker
Use x-icon blade component, nicer small-screen form size for datepicker on assets checkout
2025-04-16 21:13:21 +01:00
snipe
93e66aae54 Nicer form sizing on smaller screens
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 21:05:56 +01:00
snipe
02b831c174 Use x-icon blade component
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 21:05:43 +01:00
snipe
cd20486fe2 Merge pull request #16667 from Godmartinz/user-redirect-checkin-option
Adds option to redirect back to checkedInBy user for assets/licenses/accessories
2025-04-16 20:54:47 +01:00
snipe
a50befeda5 Merge remote-tracking branch 'origin/develop' 2025-04-16 20:16:18 +01:00
snipe
1464f80425 Merge pull request #16717 from Godmartinz/fix_checkin_mail_test
Adds a check for category email alert boolean, bolster Check in Test
2025-04-16 18:10:29 +01:00
Godfrey M
8f673a7e3e default checkin_email to true in category factory 2025-04-16 10:05:37 -07:00
Godfrey M
c44d037933 removed some words 2025-04-16 09:57:40 -07:00
Godfrey M
c8b5b3f176 adds a check for category checkin/out emails, also updates our test 2025-04-16 09:51:44 -07:00
snipe
ce94470a10 Added comments
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 16:41:25 +01:00
snipe
e7592eeeb9 Use disable admin CC
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 16:41:14 +01:00
snipe
46253b421e Added disableAdminCC to settings test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 16:41:04 +01:00
snipe
e2616e8039 Merge remote-tracking branch 'origin/develop' 2025-04-16 15:52:18 +01:00
snipe
7d4e77a7c8 Updated string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 15:52:05 +01:00
snipe
9a4f21e0cb Merge pull request #16716 from grokability/log_deprecations
Allow toggle for logging deprecation warnings
2025-04-16 14:28:07 +01:00
snipe
934aa3da7f Allow toggle for logging deprecation warnings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 14:25:51 +01:00
snipe
904266debe Merge remote-tracking branch 'origin/develop' 2025-04-16 09:47:18 +01:00
snipe
e4244d60f1 Check for username
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 09:47:06 +01:00
snipe
72d5783795 Merge remote-tracking branch 'origin/develop' 2025-04-16 09:19:05 +01:00
snipe
0b6c6bf1df Send email to CC addresses even if the target doesn’t have an email
Signed-off-by: snipe <snipe@snipe.net>
2025-04-16 09:18:50 +01:00
snipe
b35181c289 Removed deleted accessories (for now) from transformer
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 21:15:43 +01:00
snipe
d699fb1473 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:46:43 +01:00
snipe
277564436b Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:45:13 +01:00
snipe
87a03ec1ed Fixed test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:41:43 +01:00
snipe
fab1a6c33a Merge remote-tracking branch 'origin/develop' 2025-04-15 20:30:02 +01:00
snipe
f8833241ef Added @36864 as contributor
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:28:36 +01:00
snipe
7f62c5cbb6 Add @fvollmer as a contributor 2025-04-15 20:22:23 +01:00
snipe
93b4749993 Update @ntaylor-86 as a contributor 2025-04-15 20:20:36 +01:00
snipe
b2dac291da Merge pull request #16712 from grokability/fixes/snipe-api-token
Removed deprecation resulting in `Creation of dynamic property` error
2025-04-15 20:16:56 +01:00
Jermops
bec83d4343 Merge pull request #16713 from grokability/fix-docker-arm-buildname
Fix name of ARM docker container workflow
2025-04-15 12:16:40 -07:00
snipe
4f3b3721c4 Remove comments
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:15:44 +01:00
Jeremy Price
e5cf296b79 Fix name of ARM docker container workflow 2025-04-15 12:15:44 -07:00
snipe
e1abdd1c7b Removed deprecation resulting in Creation of dynamic property
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 20:11:26 +01:00
snipe
be73c30194 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-04-15 20:01:20 +01:00
snipe
71d8f1eb89 Merge pull request #16701 from grokability/repo-move
Update references to the repo to reflect move to Grokability org
2025-04-15 19:54:08 +01:00
snipe
451646fe4f Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 19:42:26 +01:00
snipe
68c1568345 Merge pull request #16711 from snipe/publish_assets
Updated dev CSS/LESS/JS assets
2025-04-15 19:40:48 +01:00
snipe
b5be0844ec Updated dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 19:39:58 +01:00
snipe
decc919991 Merge remote-tracking branch 'origin/develop' 2025-04-15 19:33:23 +01:00
snipe
f76e80ba68 Merge pull request #16710 from snipe/localizations/2025-04-15
Updated localization strings
2025-04-15 19:32:12 +01:00
snipe
ffbab554be Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 19:30:19 +01:00
snipe
e0b4005921 Merge remote-tracking branch 'origin/develop' 2025-04-15 16:48:17 +01:00
snipe
0be50e803e Merge pull request #16709 from snipe/#16699-fix-email-locales-when-none-set-on-user
Fixed #16699 - Better handle user locales in mailables
2025-04-15 16:44:38 +01:00
snipe
7133a1b262 Fixed test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:41:09 +01:00
snipe
5876418eed Search on email partial
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:31:03 +01:00
snipe
950472b935 Fixed typos
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:30:54 +01:00
snipe
c0c5699e38 Added public property name
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:21:02 +01:00
snipe
49fee3a211 Removed manually setting locale on mailable
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:10:54 +01:00
snipe
a21ca92c90 Added boot method to set name property for mailable
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 16:08:21 +01:00
snipe
260174dfd9 Added test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 15:46:12 +01:00
snipe
afc5e08716 Added email as searchable field in select list
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 15:45:25 +01:00
snipe
89616727a1 Remove english as default
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 15:45:11 +01:00
snipe
ba55dfb841 Fixed #16699 - added mutator for user locale
Signed-off-by: snipe <snipe@snipe.net>
2025-04-15 13:41:24 +01:00
snipe
65b956143c Merge pull request #16700 from snipe/docker-arm-size-fix
[Docker] Don't cache composer deps, remove any .git repos that creep in
2025-04-14 22:15:10 +01:00
snipe
42e1987147 Merge pull request #16702 from snipe/separate-docker-architecture-builds
Separate docker builds into Intel/ARM builds
2025-04-14 22:14:48 +01:00
Jeremy Price
545e07455b Separate docker builds into Intel/ARM builds
Now that we're moving to a paid org, we have native ARM github action
runners available, which means we can streamline our ARM-based docker
image builds by not having them run emulated.

I've switched our worker split from ubuntu/alpine to Intel/ARM...  if we
hate this we can make it 4 separate workflows, but i don't see an issue
with this one.
2025-04-14 12:55:36 -07:00
Jeremy Price
b00594052c [Docker] Don't cache composer deps, remove any .git repos that creep in
There is a failure mode in composer where if it has a connection trying to get
a dependency tarball from the github API, it will fall-back to
downloading the entire repo for the dependency and use that... and it
will cache it outside of vendor/, using a whopping 1.5G of space

that full 1.5G is _then_ copied into vendor/

```
98M     league
100M	tecnickcom
133M	laravel
323M	sebastian
681M	aws
```

for a total of a 1.8G vendor/ directory

vs the trimmed-down version with a 552M vendor/ directory

```
53M	league
30M	tecnickcom
31M	laravel
70M	sebastian
241M	aws
```

This is still a far cry from the proper 150M version when everything
works as it should, but it's still a vast improvement

```
3.2M    league
14M     laravel
30M     tecnickcom
260K	sebastian
52M     aws
```

Ideally this never happens, but it'd be great tp avoid the bloat if/when
it does..

To wit: Our ARM/Ubuntu Docker images are currently bloated because of this
issue due builds happening on an emulated ARM environment, and the resultant
performance penalties causing composer issues

All that to say, this change sets OMPOSER_CACHE_DIR to /dev/null to
avoid the caching, and then removes vendor/*/*/.git to remove that
needless bloat if it occurs. It's a no-op in general practice.
2025-04-14 11:55:20 -07:00
snipe
3ef36e7534 Merge remote-tracking branch 'origin/develop' 2025-04-14 11:02:06 +01:00
snipe
1c387795fe Merge pull request #16683 from marcusmoore/bug/sc-28755
Create default label when importing assets if none exists
2025-04-14 09:52:48 +01:00
snipe
1949e1e1e9 Merge remote-tracking branch 'origin/develop' 2025-04-14 09:26:25 +01:00
snipe
102f26cac1 Merge pull request #16676 from marcusmoore/fixes/acceptance-logging
Store accepted_at and declined_at in action log when accepting/declining assets
2025-04-14 09:18:54 +01:00
snipe
c7e89ff879 Merge pull request #16682 from akemidx/bug/sc-28860
FIXED: Location Being Overwritten By Default Location
2025-04-14 09:17:52 +01:00
r-xyz
565b8f5c7f Fixed #16689: re-add note field in API files listing for AssetModel 2025-04-13 00:33:22 +02:00
36864
3b314086f9 New method to get latest signature event
This makes the print page much tidier.
2025-04-11 16:28:54 +00:00
36864
06fc140626 Optimize eager loading of log entries 2025-04-11 16:27:29 +00:00
36864
e4bfc6c5ae Fix signatures for accessories and consumables
Also unifies the way these things are fetched.
2025-04-11 16:24:06 +00:00
Marcus Moore
b82d835f4f Remove created_by since it is not available 2025-04-10 13:59:28 -07:00
Marcus Moore
d593365c9c Create pending default status label if none exists 2025-04-10 13:38:30 -07:00
Marcus Moore
ea6a903d8a Implement tests including test failure 2025-04-10 13:29:05 -07:00
Marcus Moore
9086e5dba7 Scaffold some asset importer tests 2025-04-10 13:03:50 -07:00
akemidx
cd10cd34f4 location update bug fix and test 2025-04-10 14:46:52 -04:00
snipe
3358382358 Comment out location scoping option for now
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 21:44:38 +01:00
snipe
3eca3ecd75 Merge remote-tracking branch 'origin/develop' 2025-04-09 21:31:41 +01:00
snipe
0d6a83197a Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2025-04-09 21:29:31 +01:00
snipe
6d784e36d7 Updated language
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 21:29:27 +01:00
snipe
9c88aa6974 Merge pull request #16637 from akemidx/lastnameemail
Fixed #8188 - Added Last Name as an email format
2025-04-09 21:27:10 +01:00
akemidx
1307146831 changing where translations live. coalescing 2025-04-09 16:21:48 -04:00
Marcus Moore
e5d7bcb629 Use declinded at for action date in log 2025-04-09 11:20:46 -07:00
Marcus Moore
c2123e307a Add failing test 2025-04-09 11:20:07 -07:00
Marcus Moore
7a9d5bfc07 Add test for declining assets 2025-04-09 11:18:52 -07:00
Marcus Moore
aed798800c Improve assertions 2025-04-09 11:17:57 -07:00
Marcus Moore
dbfa952a69 Improve test name 2025-04-09 11:15:25 -07:00
Marcus Moore
aa58f08b3d Use accepted at for action date in log 2025-04-09 11:13:46 -07:00
Marcus Moore
d76871760c Add failing test 2025-04-09 11:11:30 -07:00
Marcus Moore
d29f5fa13e Implement tests 2025-04-09 11:07:47 -07:00
Marcus Moore
7275299165 Scaffold some tests 2025-04-09 11:02:56 -07:00
Godfrey M
9824f43780 added other target options to accessories and assets 2025-04-09 10:50:42 -07:00
snipe
1b7486c342 Merge pull request #16674 from spencerrlongg/bug/allow-avif-restore-and-logo
Add Support for Uploading AVIF Logo Images
2025-04-09 17:46:53 +01:00
spencerrlongg
cd9ee8af90 Add support for AVIF logo uploads and restoring avifs from public uploads
Extended the list of allowed file extensions and MIME types to include AVIF format in both backend file validation and the file input field for logo uploads. This update ensures compatibility with modern image formats.
2025-04-09 11:36:16 -05:00
snipe
cbf4fef45b Merge pull request #16671 from snipe/fixed_list_view_of_asset_files
Partial fix for #16135 - normalized asset file listing at API endpoint
2025-04-09 06:45:32 +01:00
snipe
8892a11e7e Updated tests
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 06:40:14 +01:00
snipe
fc390dd107 Merge pull request #16672 from snipe/added_missing_gate_to_some_location_methods
Added gates to printing locations
2025-04-09 06:28:38 +01:00
snipe
99dfb51d70 Fixed test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 06:23:40 +01:00
snipe
04f8ebb4d8 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 06:17:08 +01:00
snipe
41fb058adb Added gates around printing location assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 06:06:44 +01:00
snipe
f29146b319 Fixed asset file listing display at API endpoint
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 05:53:24 +01:00
snipe
ce0bd68716 RMB for file routes
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 05:52:59 +01:00
snipe
f3f26b3824 Added UploadedFilesTransformer
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 05:52:48 +01:00
snipe
7be3d6072f Removed erroneous comment
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 05:52:35 +01:00
snipe
1d030b59df Merge pull request #16592 from fvollmer/anonymous-ldap
Improve Settings: Remove username and password requirement for ldap
2025-04-09 05:19:09 +01:00
snipe
140c6b91b0 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-09 02:40:28 +01:00
snipe
07d2d8c549 Merge pull request #16669 from snipe/translations_for_skins
Fixed  #16130 - Added translations for skins, other settings
2025-04-09 02:37:17 +01:00
snipe
691ccbbebc Additional branding placeholders
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 02:32:22 +01:00
snipe
9daa09277d Added translations for skins
Signed-off-by: snipe <snipe@snipe.net>
2025-04-09 02:23:18 +01:00
snipe
79eaf62c9e Merge pull request #16668 from spencerrlongg/bug/sc-28768
Handle Potentially Unsafe File Output Better During Restore
2025-04-09 01:01:59 +01:00
spencerrlongg
dd078785ac always show unsafe files 2025-04-08 18:06:18 -05:00
spencerrlongg
12a8c54331 Handle and log skipped unsafe files during restore
Introduced a mechanism to track and log potentially unsafe files skipped during the restore process. These files are collected in an array and displayed as warnings before exiting, improving transparency and debugging capability.
2025-04-08 16:43:36 -05:00
Godfrey M
715fc2de59 more cleaning 2025-04-08 11:58:23 -07:00
Godfrey M
af53559ca3 cleaned up code 2025-04-08 11:54:50 -07:00
Godfrey M
17b8ea9c86 removed unnecessary code 2025-04-08 11:51:29 -07:00
Godfrey M
1ad96e891b added option logic to licenses 2025-04-08 11:50:45 -07:00
Jeremy Price
4e2b4195b4 Grokability-ize .well-known/security.txt 2025-04-08 11:50:03 -07:00
Godfrey M
b7492928ad reworked checkedInBy, added option logic to accessories 2025-04-08 11:43:02 -07:00
snipe
9f04254963 Merge pull request #16666 from snipe/print_view_tweaks
Added signature to licenses in print view, misc other fixes
2025-04-08 19:34:02 +01:00
snipe
10b8055b29 Added monospace class
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 19:10:16 +01:00
snipe
2b85ddeb74 Use correct date
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 19:10:06 +01:00
snipe
9017ae8545 Added category to consumable checkout
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 19:09:58 +01:00
snipe
d0359a42fb Added signature to licenses
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 18:56:34 +01:00
akemidx
7701c6097f adding username split 2025-04-08 13:21:32 -04:00
akemidx
275e1beda2 updating for conflicts and adding test 2025-04-08 13:15:28 -04:00
Godfrey M
85b67dbb71 adds redirect to user option from checkin blades 2025-04-08 10:13:27 -07:00
akemidx
f659b7631d Merge branch 'develop' into lastnameemail 2025-04-08 13:10:26 -04:00
Godfrey M
a602b2fd47 adds option to redirect back to checkedInBy user for assets 2025-04-08 10:09:43 -07:00
snipe
e0c6483b43 Merge pull request #16660 from snipe/cleanup_for_scoped_locations
Small improvements to location-by-company scoping
2025-04-08 17:57:50 +01:00
snipe
c2e12f69d8 Merge pull request #16664 from 36864/patch-1
Fixes #16661: Empty signatures in print page
2025-04-08 17:57:11 +01:00
snipe
890702f66d A few more display tweaks
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 17:47:39 +01:00
36864
dfdbc95b5c Fix empty signatures in print page
Fixes snipe#16661 

Assuming that whatever happens between the user accepting and signing for the asset and the print page being accessed isn't another user somehow signing for the same asset and it not being assigned to that second user.
2025-04-08 15:50:59 +00:00
snipe
ea365e5645 More fields visible
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 16:17:57 +01:00
snipe
548ae49c69 Small tweaks to table
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:30:07 +01:00
snipe
34f8f50a4a Use localization, turned display into table
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:13:57 +01:00
snipe
da2c760227 Renamed variables, skipped breaking out of loop
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:13:19 +01:00
snipe
a96abeac5f Use localization w/trans_choice
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:12:58 +01:00
snipe
420278c63b Nicer layout for settings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:12:36 +01:00
snipe
e0a04fe1ce Localized message
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 15:12:19 +01:00
snipe
c42f53e846 Use table layout
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 12:34:11 +01:00
snipe
44ee287cc0 Nicer formatting
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 12:34:00 +01:00
fvollmer
a56f6148fc Improve Settings: Remove username and password requirement for ldap
Since 9d62793 anonymous LDAP login is available. Remove username and password requirement in settings dialog.
2025-04-08 11:04:37 +02:00
snipe
5b1d6dbe14 Merge pull request #12577 from Toreg87/feature/locations_with_companies
Added #2353: Add ability to tie locations to companies - 2023 edition
2025-04-08 09:54:37 +01:00
snipe
43c15ef134 Merge branch 'develop' into feature/locations_with_companies 2025-04-08 09:18:48 +01:00
snipe
a5315ec240 Merge remote-tracking branch 'origin/develop' 2025-04-08 08:32:25 +01:00
snipe
a7203b0bbf Updated links, added mobile apps
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 08:32:15 +01:00
snipe
a14d3ad856 Merge pull request #16493 from snipe/min_qty_in_bulk_model_edit
Add min_qty to asset model bulk edit
2025-04-08 08:22:03 +01:00
snipe
fcd0ca3b94 Merge branch 'develop' into min_qty_in_bulk_model_edit 2025-04-08 07:14:15 +01:00
snipe
90329a2b2f Merge pull request #16529 from Godmartinz/location_tab_active-n-scroll_bar_fix
Fix active table tab and double scroll bar under locations
2025-04-08 07:12:33 +01:00
snipe
7448f67e12 Merge pull request #16658 from snipe/fix_bad_data_on_permission_groups
Set empty array if group permission is a string or null
2025-04-08 07:10:02 +01:00
snipe
22be89fbea Set empty array if group permission is a string or null
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 07:06:56 +01:00
snipe
93f1656e0b Merge remote-tracking branch 'origin/develop' 2025-04-08 06:51:21 +01:00
snipe
fe65ffc384 Merge pull request #16527 from Godmartinz/license_seat_notes_fix
add notes as fillable to license seat model
2025-04-08 06:49:26 +01:00
snipe
d44553c6dd Merge pull request #16553 from marcusmoore/tests/user-show
Added tests around emailing and printing assigned assets
2025-04-08 06:48:39 +01:00
snipe
cfd845aefa Merge pull request #16500 from marcusmoore/bug/sc-28644-command
Added command to fix bulk checkin action log entries
2025-04-08 06:44:25 +01:00
snipe
a98b277fa9 Merge pull request #16560 from spencerrlongg/bug/meta_status_multi_comp
Meta Status Fix for Multi Company
2025-04-08 06:43:57 +01:00
snipe
237975577d Merge pull request #16636 from marcusmoore/tests/delete-asset-tests
Added tests around deleting assets
2025-04-08 06:32:40 +01:00
snipe
2275186222 Merge pull request #16652 from akemidx/feature/sc-28820
Username dropdown to show Usernames and not Emails as Examples
2025-04-08 06:32:19 +01:00
snipe
f1d006c236 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-08 05:58:51 +01:00
snipe
5a1c81954f Merge pull request #16651 from Godmartinz/qr_code_location_option
Fixes #9660 - Adds location qr code option to labels
2025-04-08 05:53:48 +01:00
snipe
68e7d172a4 Merge pull request #16655 from snipe/adds_more_searchable_relations_to_activity
Fixed #13274 - Adds more searchable relations to activity report
2025-04-08 05:53:18 +01:00
snipe
b2e0f48ed9 Added purchase date
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:50:03 +01:00
snipe
733ef9e23b Few more
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:44:49 +01:00
snipe
83562cfa83 Added additional searchable relations to activity report
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:23:39 +01:00
snipe
de426c2d2c Merge pull request #16653 from snipe/add_audit_custom_fields
Fixed #13475 - Add custom fields to audit screen
2025-04-08 05:16:23 +01:00
snipe
05e66c33ee Added audits string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:09:08 +01:00
snipe
744e844291 Added audit tab
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:08:58 +01:00
snipe
31c9ffa32b Added audits method
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:08:42 +01:00
snipe
c46a9a773d Fixed admin string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 05:08:08 +01:00
snipe
849da2fb63 Use correct audit icon
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 04:15:59 +01:00
snipe
b51939ae76 Derp. Use correct model info
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 04:07:31 +01:00
snipe
e95d7076b9 Added action_date
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 04:07:04 +01:00
snipe
d2c7385197 Updated class for error text
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 04:06:54 +01:00
snipe
5beb0bf534 Added assertion for success in test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:39:17 +01:00
snipe
c59e9770b7 Removed unusued property
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:39:05 +01:00
snipe
908bb35792 Use upload file request
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:38:35 +01:00
snipe
c4d0afb8d4 Added comments
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:24:33 +01:00
snipe
4b21f0d00b Removed stray character
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:03:45 +01:00
snipe
4aeba2a96b Try to fix tests
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:02:37 +01:00
snipe
74f8cb5298 Updated url in bootstrap partial
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:02:28 +01:00
snipe
62e863a0fa Removed tooltip code
This throws an error currently

Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:02:10 +01:00
snipe
5bbba56b0e Added orginal values for logging
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:01:39 +01:00
snipe
e4180c2194 Removed duplicated code
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:01:29 +01:00
snipe
f4e3e6ceb6 Added display_audit to custom fields transformer
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:01:08 +01:00
snipe
f37ed3e055 Add display_audit to custom fields controller
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:00:51 +01:00
snipe
9bb349d34b Try to get the asset from the route if there is RMB
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 02:00:37 +01:00
snipe
362f14a01d Manually invoke a validator
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 01:59:33 +01:00
snipe
226ad52f07 Better UI route
Signed-off-by: snipe <snipe@snipe.net>
2025-04-08 01:59:08 +01:00
akemidx
443a5c2348 chaning username dropdown to be usernames and not emails 2025-04-07 19:25:32 -04:00
snipe
ce460c9ab0 Updated route
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:15:09 +01:00
snipe
c344c40310 Added auditAssets() to user factory
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:10:36 +01:00
snipe
95fef9682f Added migration
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:10:18 +01:00
snipe
241777c1fd Added translation string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:10:12 +01:00
snipe
acdbf452e2 Added checkbox to custom field form
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:10:01 +01:00
snipe
b8a9db2faf Added display_audit to custom fields list
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:09:51 +01:00
snipe
dfdc24936d Added custom fields partial
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:09:29 +01:00
snipe
6a1bb06c13 Added tests
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:09:14 +01:00
snipe
cfa8ddffc0 Keep legacy URL for audit
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:08:05 +01:00
snipe
5b524399d9 Use RMB for asset audit API
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 22:07:51 +01:00
Godfrey M
bc3b3cf86e add psuedo example location_id for preview 2025-04-07 12:53:17 -07:00
Godfrey M
a69133e2ae adds location qr code option to labels 2025-04-07 12:36:05 -07:00
snipe
b0b5a96694 Merge remote-tracking branch 'origin/develop' 2025-04-07 13:54:23 +01:00
snipe
b66618ff3f Fixed typo
Signed-off-by: snipe <snipe@snipe.net>
2025-04-07 13:54:10 +01:00
snipe
7dbe9a85f4 Merge remote-tracking branch 'origin/develop' 2025-04-05 21:02:33 +01:00
snipe
b5ef856d9e Translate request cancel string
Signed-off-by: snipe <snipe@snipe.net>
2025-04-05 17:24:06 +01:00
snipe
a302cc145a Merge pull request #16643 from snipe/small_requestable_improvements
Text tweaks and nicer buttons for requestable items
2025-04-05 16:07:57 +01:00
snipe
d203c4e49c Text tweaks and nicer buttons
Signed-off-by: snipe <snipe@snipe.net>
2025-04-05 15:58:03 +01:00
snipe
d2c39528d5 Merge remote-tracking branch 'origin/develop' 2025-04-05 15:44:22 +01:00
snipe
b5c7e60408 Merge pull request #16642 from snipe/fixed_#16640-FIFO-for-requestable
Fixed #16640 - FIFO for requestable assets
2025-04-05 15:39:29 +01:00
snipe
3684e9c1e8 Fixed #16640 - FIFO for requestable assets
Signed-off-by: snipe <snipe@snipe.net>
2025-04-05 15:38:13 +01:00
snipe
0420543c94 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-05 14:11:07 +01:00
snipe
f2c730bd57 Fix wrapping on #16628
Signed-off-by: snipe <snipe@snipe.net>
2025-04-05 14:10:23 +01:00
akemidx
f0bf77735d adding last name only as a email choice 2025-04-03 23:34:04 -04:00
Marcus Moore
1b95b29832 Add tests for deleting asset via ui 2025-04-03 16:12:13 -07:00
Marcus Moore
9a8e5bf61e Backup before running updates 2025-04-03 14:39:40 -07:00
Marcus Moore
18ef88bd67 Improve comment 2025-04-03 13:13:52 -07:00
Marcus Moore
4ba58b2546 Constrain query 2025-04-03 13:10:45 -07:00
Marcus Moore
6dd3ab2ec9 Exit early if no logs found 2025-04-03 12:56:46 -07:00
Marcus Moore
faee50c222 Use dry-run instead of dryrun 2025-04-03 12:56:07 -07:00
Jeremy Price
afd9282785 Update remaining comments from snipe/snipe-it to grokability/snipe-it 2025-04-03 12:07:05 -07:00
Jeremy Price
1344ed1d16 Update app & composer files from snipe/snipe-it to grokability/snipe-it 2025-04-03 12:04:12 -07:00
Jeremy Price
cbea096403 Update Vagrantfile files from snipe/snipe-it to grokability/snipe-it 2025-04-03 12:02:42 -07:00
Jeremy Price
094edbd114 Update css and less files from snipe/snipe-it to grokability/snipe-it 2025-04-03 12:00:51 -07:00
Jeremy Price
f016b6b988 Update relevant README sections from snipe/snipe-it to grokability/snipe-it 2025-04-03 11:54:39 -07:00
Jeremy Price
782b35e0f1 Update scripts from snipe/snipe-it to grokability/snipe-it 2025-04-03 11:51:12 -07:00
Jeremy Price
70e9c6b947 Update relevant snipe/snipe-it references to grokability/snipe-it in Docker files 2025-04-03 11:44:27 -07:00
Jeremy Price
4a457c96e8 Update Contributors links from snipe/snipe-it to grokability/snipe-it 2025-04-03 11:39:21 -07:00
Jeremy Price
2e2516825e Update github workflows from snipe/snipe-it to grokability/snipe-it 2025-04-03 11:36:57 -07:00
snipe
aae0db902b Merge remote-tracking branch 'origin/develop' 2025-04-03 15:41:08 +01:00
snipe
ba621cb1f2 Merge pull request #16632 from uberbrady/fix_paveit_command
Paveit had old Doctrine code to list tables; use the new method
2025-04-03 15:39:38 +01:00
snipe
b1e2b5ab4a Merge pull request #16623 from Godmartinz/accessories_history_view_fix
Fixes Accessories history table color contrast
2025-04-03 15:37:55 +01:00
snipe
7c1438c370 Merge pull request #16446 from marcusmoore/feature/improve-checkout-asset-mail-wording
Improved wording in asset checkout emails
2025-04-03 15:37:30 +01:00
Brady Wetherington
760768f42d Paveit had old Doctrine code to list tables; use the new method 2025-04-03 15:35:07 +01:00
snipe
88dae7cef7 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2025-04-03 15:28:10 +01:00
snipe
cc8c2064c1 Merge pull request #16630 from snipe/license_key_formatting
Fixed #16628 - added formatting for license keys
2025-04-03 15:26:14 +01:00
snipe
33a921119c Merge pull request #16631 from snipe/add_webp_to_inline
Added webp as inline-able images
2025-04-03 15:25:48 +01:00
snipe
0e65498799 Added webp as inline-able images
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 15:24:03 +01:00
snipe
274c5fe4d3 Added max-width
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 15:07:10 +01:00
snipe
b7c011dd2d Use new one line code style
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 15:03:31 +01:00
snipe
a4a99adf80 Added one-line code style
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 15:03:16 +01:00
snipe
c7890f4c3b Use id as copy key
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 13:52:55 +01:00
snipe
6d7f061a1d Larger key box
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 13:39:31 +01:00
snipe
45d3c0444b Added copy to license keys
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 12:29:30 +01:00
snipe
9204309d67 Checkin/Checkout note added to language file
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 12:28:47 +01:00
snipe
a2035693e6 Added licenseKeyFormatter
Signed-off-by: snipe <snipe@snipe.net>
2025-04-03 12:28:30 +01:00
snipe
e5cb17e934 Merge remote-tracking branch 'origin/develop' 2025-04-03 10:16:18 +01:00
akemidx
392db81499 requested changes 2025-04-02 21:28:34 -04:00
snipe
abfea8e349 Merge pull request #16624 from snipe/bug/sc-28682
Fixed [SC-28682] - Consumable import not importing supplier and item number
2025-04-03 01:45:52 +01:00
snipe
ef20bd4aa8 Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:41:12 +01:00
snipe
2d9be4e9e0 Added supplier_id as fillable
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:10:25 +01:00
snipe
36767c0a5c Added more common fields for mapping
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:10:16 +01:00
snipe
0d099263e3 Removed unneeded lines
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:09:28 +01:00
snipe
8f50e01d18 Shrink sample CSVs
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:09:04 +01:00
snipe
d898288397 Remove email user for comonent import type
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 21:08:54 +01:00
Marcus Moore
af88ce5801 Merge branch 'develop' into feature/improve-checkout-asset-mail-wording 2025-04-02 12:01:53 -07:00
Godfrey M
b1b248f03d removed duplicate class from accessories history table 2025-04-02 11:29:01 -07:00
snipe
9d609805f2 Merge remote-tracking branch 'origin/develop' 2025-04-02 18:33:48 +01:00
snipe
df1c7c4f95 Merge pull request #16609 from snipe/login_throttle_update
Updated login attempts and throttle duration
2025-04-02 18:28:34 +01:00
snipe
7120b19d3b Fixed namespace
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 18:24:27 +01:00
snipe
e2b9ca8254 Merge remote-tracking branch 'origin/develop' 2025-04-02 14:03:22 +01:00
snipe
2197b46658 Link to admin user
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 14:03:09 +01:00
snipe
e16a2fe8af Merge remote-tracking branch 'origin/develop' 2025-04-02 13:51:09 +01:00
snipe
785f576b19 Merge pull request #16621 from snipe/add_notes_to_location_sidebar
Fixed #16618 - added notes to location sidebar
2025-04-02 13:27:48 +01:00
snipe
31e337255a Use adminuser instead of created_by
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 13:26:12 +01:00
snipe
f12d173581 Fixed #16618 - added notes to location sidebar
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 13:23:33 +01:00
snipe
22d61a533d Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-04-02 12:50:35 +01:00
snipe
eb3dbb8c7a Bumped hash
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:49:53 +01:00
snipe
ed908be2eb Merge pull request #16620 from snipe/#16619_fix_accessory_clone_population
Fixed #16619 - cloning accessory was not populating fields
2025-04-02 12:48:25 +01:00
snipe
e215c5f9ee Fixed #16619 - accesory clone
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:43:42 +01:00
snipe
78f3c879ff Merge pull request #16617 from snipe/add_pdf_logo_upload
Fixed #16257 - Added acceptance PDF logo upload
2025-04-02 12:22:43 +01:00
snipe
cb59c23f0b Added pdf logo to the blade
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:13:34 +01:00
snipe
d0f750edea Added pdf logo to the controller
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:13:28 +01:00
snipe
56ae9d0ba9 Nicer upload logo labels
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:10:27 +01:00
snipe
15917d5f99 Use new logo
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:10:14 +01:00
snipe
a59d69cb0d Updated strings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:10:05 +01:00
snipe
97cba45509 Added migration
Signed-off-by: snipe <snipe@snipe.net>
2025-04-02 12:09:57 +01:00
snipe
365ce34940 Merge pull request #16613 from marcusmoore/chore/update-rollbar
Update rollbar-laravel to 8.1
2025-04-02 10:48:51 +01:00
Marcus Moore
7048eceb9d Update rollbar/rollbar-laravel 2025-04-01 16:05:32 -07:00
snipe
af408bb45f Merge remote-tracking branch 'origin/develop' 2025-04-01 21:33:07 +01:00
snipe
9d61234f0c Merge pull request #16612 from snipe/re-fix_db_dump_ssl_fix
Fixes #16610, regression in #16543
2025-04-01 21:32:15 +01:00
snipe
bef650757d Fixes #16610, regression in #16543
Signed-off-by: snipe <snipe@snipe.net>
2025-04-01 21:25:35 +01:00
snipe
24bfbc06f0 Merge remote-tracking branch 'origin/develop' 2025-04-01 19:40:03 +01:00
snipe
cb6e7f7b6e Merge pull request #16561 from spencerrlongg/bug/api_get_by_serial_add_pagination
Adds Pagination to Hardware By Serial API Request
2025-04-01 19:26:28 +01:00
snipe
c305284930 Merge pull request #15922 from spencerrlongg/feature/sc-24347
Requestable/Request Item API Endpoints
2025-04-01 18:15:42 +01:00
snipe
6c47f1c07f Added test
Signed-off-by: snipe <snipe@snipe.net>
2025-04-01 17:44:44 +01:00
snipe
5d265f5bfd Change to minutes
Signed-off-by: snipe <snipe@snipe.net>
2025-04-01 15:01:34 +01:00
snipe
daaad4fe9d Removed unneeded strings
Signed-off-by: snipe <snipe@snipe.net>
2025-04-01 14:36:53 +01:00
snipe
40ae5d421b Updated maxLoginAttempts and throttle duration
Signed-off-by: snipe <snipe@snipe.net>
2025-04-01 14:36:45 +01:00
snipe
5eb9f353b5 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
2025-04-01 11:25:33 +01:00
akemidx
d96498ab1f this is a redo after a borked rebase 2025-03-31 18:33:20 -04:00
spencerrlongg
bfd827e529 added more eager loading 2025-03-31 12:28:03 -05:00
snipe
d95549bbcf Merge pull request #16594 from uberbrady/fix_consumable_model_copy
Fixes [FD-47675 ] Fix consumable model number copy-to-clipboard button
2025-03-31 18:26:46 +01:00
snipe
e10071a68e Merge pull request #16595 from uberbrady/fix_whitespace_encrypted_custom_fields_display
Fix whitespace encrypted custom fields display [FD-46570]
2025-03-31 18:25:13 +01:00
Brady Wetherington
92a77afd0b Fixes the clipboard button copying whitespace at the end of custom fields 2025-03-31 13:55:38 +01:00
Brady Wetherington
1369b993a4 Fix JS copy-to-clipboard for consumable model_num 2025-03-31 13:13:37 +01:00
snipe
382414df98 Merge pull request #16559 from Godmartinz/StoreLabelSettings_fix
Fix Form save error when using old label engine
2025-03-31 12:39:08 +01:00
snipe
6846c7d510 Merge pull request #16536 from akemidx/moving_warranty_info
Moving warranty/depreciation to be with the other cost/eol values
2025-03-31 12:35:32 +01:00
snipe
1d3069fe84 Merge pull request #16540 from marcusmoore/bug/sc-28607
Early return null from location transformer for missing accessory
2025-03-31 12:34:22 +01:00
snipe
13940071a9 Merge pull request #16546 from marcusmoore/bug/sc-28024
Fixed potential bad method call and premature email sending in bulk asset checkout
2025-03-31 12:32:50 +01:00
snipe
6870698cdc Add @ntaylor-86 as a contributor 2025-03-31 12:32:25 +01:00
snipe
4aa13c8dd4 Merge pull request #16543 from ntaylor-86/fixes/laravel-backup-ssl-error
Fixed #16217: database config, added option to skip ssl on the database dump
2025-03-31 12:32:00 +01:00
snipe
44db2dc78e Merge pull request #16520 from marcusmoore/bug/sc-28673
Remove unneeded eager loading for user show page
2025-03-31 12:31:12 +01:00
snipe
2e17e80ea9 [Snyk] Upgrade acorn from 8.14.0 to 8.14.1 #16587
Signed-off-by: snipe <snipe@snipe.net>
2025-03-31 12:30:09 +01:00
snipe
836d7ca8f9 [Snyk] Upgrade bootstrap-table from 1.24.0 to 1.24.1 #16588
Signed-off-by: snipe <snipe@snipe.net>
2025-03-31 12:29:00 +01:00
snipe
18e6a18389 Merge pull request #16576 from marcusmoore/fixes/api_company_note
Fixed notes not being saved and update for companies via api
2025-03-31 12:20:36 +01:00
snipe
1dd050ac0f Merge pull request #16577 from marcusmoore/tests/login-logging
Added tests around login attempt logging
2025-03-29 23:30:05 -01:00
Marcus Moore
b8b0e3200e Add tests around loggin login attempts 2025-03-27 17:27:28 -07:00
Marcus Moore
bc77c8c885 Add notes to $fillable 2025-03-27 10:57:34 -07:00
Marcus Moore
c095f330e1 Add failing tests 2025-03-27 10:56:33 -07:00
Marcus Moore
e0e08f284e Add tests for creating and patching companies via api 2025-03-27 10:54:42 -07:00
spencerrlongg
e273c7cbc5 Refactor asset retrieval to support pagination.
Introduced offset and limit handling for API asset queries to enable proper pagination. Adjusted the total count logic to maintain consistency in responses and ensure accurate transformation of assets.
2025-03-25 15:21:18 -05:00
Godfrey M
d28cc024cf add DefaultLabel if no label2_template is selected 2025-03-25 12:40:23 -07:00
spencerrlongg
168a3df157 Fix condition in statusMeta for correct property check
Updated the conditional check to use 'assigned_to' instead of 'assigned' for determining the deployment status. This ensures the code references the correct property on the model.
2025-03-25 14:39:51 -05:00
Marcus Moore
ac597b517b Remove blank line 2025-03-24 12:39:17 -07:00
Marcus Moore
ac56640d40 Spilt test scenarios 2025-03-20 16:21:42 -07:00
Marcus Moore
ce585539aa Improve test name 2025-03-20 16:13:13 -07:00
Marcus Moore
2cfff8e07c Formatting 2025-03-20 16:12:31 -07:00
Marcus Moore
0ceda098ff Spilt test scenarios 2025-03-20 16:10:01 -07:00
Marcus Moore
db81209fe1 Organize existing tests 2025-03-20 16:01:28 -07:00
Marcus Moore
02f109c3b5 Include input when redirecting back 2025-03-20 14:04:19 -07:00
Marcus Moore
0ed0a7f9f3 Avoid sending emails for asset checkouts that failed 2025-03-20 14:01:48 -07:00
Marcus Moore
b721b7d9c9 Add tests 2025-03-20 13:57:42 -07:00
Marcus Moore
976b3dc5ae Improve test case 2025-03-20 13:38:12 -07:00
snipe
2d3514bbf8 Merge pull request #16545 from Godmartinz/activity_report_column_name_fix
changes translation from Admin Settings to Created By on the Activity Report
2025-03-20 19:37:42 -01:00
Marcus Moore
5dcd4b2942 Return valid error message 2025-03-20 13:26:27 -07:00
Marcus Moore
d645b42e12 Add failing test 2025-03-20 13:26:06 -07:00
Godfrey M
0ad985cbcd change translation 2025-03-20 12:40:46 -07:00
ntaylor-86
ad5099fac9 added .env variable to the other .env files 2025-03-20 23:27:29 +10:00
ntaylor-86
32736e2f74 added .env variable and database config to skip ssl for DB DUMP 2025-03-20 23:06:15 +10:00
Marcus Moore
cef83ad652 Avoid hard failure on missing accessory in location transformer 2025-03-19 14:11:47 -07:00
Marcus Moore
e6ccff103f Add simple null check to avoid attempting to transform missing relationship 2025-03-19 12:52:01 -07:00
akemidx
5944034b8b moving warranty/depreciation to be with the other cost/eol values 2025-03-19 15:22:09 -04:00
snipe
473ce15f47 Merge pull request #16526 from snipe/develop
Merge #16486  and #16519 into master
2025-03-19 15:31:50 -01:00
Godfrey M
881cde4d98 change namesspaces and use create instead of make 2025-03-18 14:18:49 -07:00
akemidx
e408b902f0 removing depreciation from purchase cost (unneeded, should go elsewhere if wanted) 2025-03-18 16:38:44 -04:00
akemidx
a398c4ab84 reset 2025-03-18 16:37:27 -04:00
akemidx
27417cdec7 removing depreciation logic (unneeded for purchase cost) 2025-03-18 16:36:36 -04:00
Godfrey M
bf3837c49d add checkin test for api 2025-03-18 12:54:03 -07:00
Godfrey M
66fd46fe75 add checkout test for api 2025-03-18 12:46:56 -07:00
Godfrey M
29cbf43d68 remove duplicate table class div 2025-03-18 11:48:09 -07:00
Godfrey M
07096c8a31 rename note to notes 2025-03-18 10:37:00 -07:00
Godfrey M
cbc6c2754c add notes as fillable to license seat model 2025-03-18 10:27:56 -07:00
Jermops
711235f49c Merge pull request #16519 from marcusmoore/bug/sc-28696
Fixed issue with bad email addresses in expiration alerts and upcoming audits
2025-03-18 09:15:41 -07:00
Jeremy Price
3d2d7684aa Add console command to disable SAML logins
If a Snipe-IT sire has SAML enabled, and the SAML config is sufficiently
borked, the site will fail to even load the login page. That's probably
something that should be examined, but in the meantime, it'd be handy to
not have to manually edit the database to turn off SAML.

In this commit, I'm creating a saml-disable console command. And by
create, i mean i'm copypasta-ing the existing ldap-disable command.
2025-03-17 19:58:21 -07:00
Marcus Moore
9aede45918 Remove unneeded eager loads 2025-03-17 14:43:23 -07:00
Marcus Moore
b26a73e385 Filter out empty email address in alerts 2025-03-17 12:30:15 -07:00
Marcus Moore
650839b68a Update command name 2025-03-12 17:05:16 -07:00
Marcus Moore
388dc23241 Add comments 2025-03-12 17:02:05 -07:00
Marcus Moore
32b194ddc7 Update description 2025-03-12 16:44:37 -07:00
Marcus Moore
9cea6cee26 Docblock 2025-03-12 16:42:50 -07:00
Marcus Moore
73f64c53b1 Skip logs where created_by cannot be set 2025-03-12 16:42:39 -07:00
Marcus Moore
2091f66f5b Reorganize 2025-03-12 16:30:36 -07:00
snipe
c711278b8b Merge pull request #16486 from marcusmoore/bug/sc-28639
Fixed location being automatically populated on asset checkin screen
2025-03-12 23:26:08 +00:00
snipe
eb9cfbaed6 Merge pull request #16498 from snipe/develop
Merge develop into master
2025-03-12 23:23:44 +00:00
snipe
ff637f1926 Merge pull request #16497 from marcusmoore/fixes/diff-in
Fixed various carbon displays
2025-03-12 23:17:48 +00:00
Marcus Moore
4d978e0fc6 Fix eol rate in upcoming audit notification 2025-03-12 16:04:16 -07:00
Marcus Moore
167001ed54 Fix eol rate in tests 2025-03-12 16:01:32 -07:00
Marcus Moore
25fb1abc95 Fix eol rate in AssetObserver 2025-03-12 15:58:11 -07:00
Marcus Moore
658bef447d Fix eol rate in Actionlog 2025-03-12 15:55:13 -07:00
Marcus Moore
a28ff22d03 Fix eol rate in ReportsController 2025-03-12 15:44:06 -07:00
Marcus Moore
63a1ee0047 Fix eol rate in AssetMaintenancesController 2025-03-12 15:38:54 -07:00
Marcus Moore
ab8f4454d1 Add failing test for updating asset maintenance 2025-03-12 15:38:46 -07:00
Marcus Moore
e439f1f42b Fix eol rate in AssetMaintenancesController 2025-03-12 15:35:46 -07:00
Marcus Moore
9be27bdf07 Add failing test for creating asset maintenance 2025-03-12 15:35:14 -07:00
snipe
faeb037ff9 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/mix-manifest.json
2025-03-12 21:26:34 +00:00
snipe
bfc122469c Merge pull request #16495 from snipe/add_highlight_for_low_qty
Added highlight to items when the remaining is less than the min_amt
2025-03-12 21:23:15 +00:00
snipe
036c225dcf Fixed dashboard string
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 21:22:24 +00:00
snipe
083cf78305 Added footer style for nicer number cell padding
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 21:17:41 +00:00
Marcus Moore
824271078e Fix eol rate in AssetsController 2025-03-12 13:55:12 -07:00
Marcus Moore
1122cd8567 Fix eol rate in asset transformer 2025-03-12 13:33:15 -07:00
Marcus Moore
6cf7df22cd Fix eol rate on asset show page 2025-03-12 13:28:34 -07:00
snipe
7421d089ff Added formatter and centering in presenters
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 20:25:00 +00:00
snipe
bdb4bd73d2 Return an indicator for no value set
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 20:18:51 +00:00
snipe
bf88597132 Added qtySumFormatter and made seats formatter more generic
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 20:14:23 +00:00
snipe
dfacd876d5 Added remaining/min_amt to transformers
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 20:13:15 +00:00
Marcus Moore
d5bc5caacd Purge activity log of consumable bulk checkins 2025-03-12 11:57:18 -07:00
Marcus Moore
be6caf936e Avoid logging consumable checkins 2025-03-12 11:48:14 -07:00
snipe
f1e70eb7a0 Add min_qty to asset model bulk edit
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 18:27:27 +00:00
snipe
07602f697d Merge remote-tracking branch 'origin/develop' 2025-03-12 18:13:22 +00:00
snipe
dbe78c30d5 Merge pull request #16491 from snipe/bug/sc-28671
Fixed new user modal pre-populating with first name and last name of acting user
2025-03-12 18:05:57 +00:00
snipe
c1601b9a8c Updated tests
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 17:28:50 +00:00
snipe
aa8e9f61d2 Check for value override
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 17:28:44 +00:00
snipe
163ddc8026 Check for value override
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 17:28:29 +00:00
snipe
c73dba4a43 Better visual spacing
Signed-off-by: snipe <snipe@snipe.net>
2025-03-12 17:28:05 +00:00
snipe
5e61a814a7 Merge pull request #16489 from marcusmoore/bug/sc-28644
Fixed timestamp in action log for bulk accessory check in
2025-03-12 14:56:52 +00:00
Marcus Moore
935d3eea9f Attempt to match and populate created_by 2025-03-11 17:17:39 -07:00
Marcus Moore
fffc606d9a Improve output 2025-03-11 17:06:02 -07:00
Marcus Moore
c3a48182fd Display the created_by 2025-03-11 17:03:26 -07:00
Marcus Moore
147e610062 Add todos 2025-03-11 17:00:36 -07:00
Marcus Moore
dd14eac1eb Prompt for confirmation 2025-03-11 16:56:07 -07:00
Marcus Moore
4954d972bb Write table of ids 2025-03-11 16:52:20 -07:00
Marcus Moore
c8177eb51e Update timestamps 2025-03-11 16:50:16 -07:00
Marcus Moore
a8cccffa1e Update output 2025-03-11 16:41:22 -07:00
Marcus Moore
c774e969d7 Scaffold command 2025-03-11 16:34:07 -07:00
Marcus Moore
b5fa538a54 Set created_by correctly in he action log 2025-03-11 16:05:02 -07:00
snipe
11abb0fdb1 Merge remote-tracking branch 'origin/develop' 2025-03-11 22:13:34 +00:00
snipe
fcdc1494c2 Merge pull request #16443 from azmcnutt/feature/labels_Avery_5520_1DBarcode
Nice work! Thank you!
2025-03-11 22:12:09 +00:00
snipe
badb367e74 Merge pull request #16445 from ubc-cpsc/bugfix/CVE-2025-27515
Fixes CVE-2025-27515: Laravel has a File Validation Bypass
2025-03-11 21:55:58 +00:00
snipe
2960a13772 Upgrade webpack from 5.97.1 to 5.98.0 #16461
Signed-off-by: snipe <snipe@snipe.net>
2025-03-11 21:24:44 +00:00
snipe
deeb2fa543 Merge remote-tracking branch 'origin/develop' 2025-03-11 21:14:12 +00:00
snipe
5e10c213f6 Merge pull request #16488 from marcusmoore/bug/sc-28631
Nice catch!
2025-03-11 21:05:46 +00:00
snipe
b61eacbdab Merge pull request #16473 from marcusmoore/chore/replace-form-close
Replaced call to Form::close()
2025-03-11 20:47:08 +00:00
Marcus Moore
e2f643e7ed Backfill tests 2025-03-11 13:46:21 -07:00
Marcus Moore
9cbcfba4e9 Add test 2025-03-11 13:35:50 -07:00
Marcus Moore
fd854072b0 Properly handle route model bound LicenseSeat not being found 2025-03-11 13:03:00 -07:00
Marcus Moore
18b208bba2 Account for missing location 2025-03-11 11:46:38 -07:00
Marcus Moore
71d93ca3c3 Use dedicated location select component
Copy/paste/modify from partials.forms.edit.location-select
2025-03-11 11:41:26 -07:00
Marcus Moore
bac2760c6d Replace Form::close 2025-03-10 12:55:35 -07:00
snipe
33c9ea4bb1 Merge pull request #16065 from marcusmoore/chore/migrate-select-helper
Convert  Form::select to blade component
2025-03-07 01:05:58 +00:00
Marcus Moore
d88fe1f48a Merge branch 'develop' into chore/migrate-select-helper 2025-03-06 13:39:05 -08:00
Marcus Moore
f202817852 Use translation strings 2025-03-06 12:43:59 -08:00
Joël Pittet
618d81777a Fixes CVE-2025-27515 2025-03-06 12:33:29 -08:00
James M
0b6d810ca6 FEAT: Add Label 5520 with 1D barcode - remove 2D barcode
FEAT: Add Label 5520 with 1D barcode - remove 2D barcode
2025-03-06 11:12:16 -07:00
snipe
8c164d1b09 Merge pull request #16441 from snipe/added_modal_tests
Added modal tests
2025-03-06 15:06:08 +00:00
snipe
6d74053ca3 Added modal tests
Signed-off-by: snipe <snipe@snipe.net>
2025-03-06 15:02:55 +00:00
snipe
ef8d5ff11e Merge remote-tracking branch 'origin/develop' 2025-03-06 12:06:10 +00:00
snipe
f42fcd25b1 Make the assets tab active by default on locations page
Signed-off-by: snipe <snipe@snipe.net>
2025-03-06 12:05:36 +00:00
Marcus Moore
7df636515f Move to data providers 2025-03-05 18:20:40 -08:00
Marcus Moore
3db124e709 First pass at updating wording for asset checkout mail 2025-03-05 18:12:23 -08:00
snipe
c5dd942f3d Merge pull request #16436 from marcusmoore/fixes/report-template-link
Fixed linking in saved report template dropdown
2025-03-06 01:06:18 +00:00
Marcus Moore
70de08a211 Replace hard-coded link to report template 2025-03-05 16:26:26 -08:00
Marcus Moore
d1683d1c65 Use existing translation string 2025-03-05 16:10:36 -08:00
Marcus Moore
f038254038 Have UI reflect not being able to delete accessory 2025-03-05 16:02:23 -08:00
Marcus Moore
a19582a5f3 Prevent deleting accessory that has checkouts via api 2025-03-05 15:58:34 -08:00
Marcus Moore
00cbebd1e3 Add failing test for api 2025-03-05 15:57:18 -08:00
Marcus Moore
8c21d625fc Prevent deleting accessory that has checkouts via UI 2025-03-05 15:56:01 -08:00
snipe
64f49afce1 Merge pull request #16432 from marcusmoore/bug/sc-24475
Added validation around user store endpoint
2025-03-05 20:16:30 +00:00
Marcus Moore
25395e9af1 Add test for storing user 2025-03-05 11:37:03 -08:00
Marcus Moore
69009e027f Add authorization test 2025-03-05 11:34:45 -08:00
Marcus Moore
695c9d070f Require int for department and company ids when creating user via api 2025-03-05 11:32:04 -08:00
snipe
91f3e07b83 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

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

# Conflicts:
#	public/css/dist/skins/_all-skins.css
#	public/css/dist/skins/_all-skins.min.css
#	public/css/dist/skins/skin-blue.css
#	public/css/dist/skins/skin-blue.min.css
#	public/mix-manifest.json
2025-03-05 13:46:29 +00:00
snipe
27d98fbb93 Merge pull request #16429 from snipe/bug/sc-28609
Updated HTML label colors in blue skin
2025-03-05 13:43:53 +00:00
snipe
0e1f40626f Updated label colors in blue skin
Signed-off-by: snipe <snipe@snipe.net>
2025-03-05 13:40:36 +00:00
snipe
a20d104d2f Merge remote-tracking branch 'origin/develop' 2025-03-05 11:59:47 +00:00
snipe
7a312d075c Check for null on webhook url
Signed-off-by: snipe <snipe@snipe.net>
2025-03-05 11:59:35 +00:00
snipe
a61dd8ac17 Merge remote-tracking branch 'origin/develop' 2025-03-05 10:52:42 +00:00
snipe
e1156be919 Merge pull request #16427 from snipe/fixed_user_modal_email
Fixes user create modal - check if $item is set
2025-03-05 10:52:00 +00:00
snipe
fcf7a543fd Check if $item is set
Signed-off-by: snipe <snipe@snipe.net>
2025-03-05 10:47:33 +00:00
Spencer Long
6201e475cb Merge branch 'develop' into feature/sc-24347 2025-03-04 21:20:46 -06:00
snipe
7ee9a690ea Merge remote-tracking branch 'origin/develop' 2025-03-05 01:12:22 +00:00
snipe
bef54983fa Merge pull request #16421 from marcusmoore/chore/migrate-label-helpers-pt8
Replace calls to Form::label pt8
2025-03-05 01:01:21 +00:00
Marcus Moore
f2b44f7002 Replace Form::label in company select partial 2025-03-04 16:46:43 -08:00
Marcus Moore
de7d32f632 Replace Form::label on ldap settings page 2025-03-04 16:44:26 -08:00
snipe
fecee69de6 Use table name to avoid ambiguous query
Signed-off-by: snipe <snipe@snipe.net>
2025-03-05 00:43:04 +00:00
snipe
75366927f0 Fixed table name
Signed-off-by: snipe <snipe@snipe.net>
2025-03-05 00:41:11 +00:00
Marcus Moore
c798df2920 Replace Form::label on label settings page 2025-03-04 16:34:22 -08:00
snipe
5ba94c6c41 Merge remote-tracking branch 'origin/develop' 2025-03-05 00:12:09 +00:00
snipe
779330af14 Merge pull request #16420 from marcusmoore/fixes/report-url
Fixed custom report template route
2025-03-05 00:11:30 +00:00
Marcus Moore
f01ff1f1d7 Add dedicated named route 2025-03-04 16:07:35 -08:00
Marcus Moore
1e4daf0348 Fix route 2025-03-04 16:04:28 -08:00
snipe
9fa855c837 Prod assets
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 23:30:45 +00:00
snipe
9251007574 Merge remote-tracking branch 'origin/develop' 2025-03-04 23:29:31 +00:00
snipe
fae79a91f6 Merge pull request #16418 from marcusmoore/chore/custom-report-template-activity-log-removal
Stop reporting report template events to activity log
2025-03-04 23:28:43 +00:00
Marcus Moore
e8ee218f39 Purge activity log of report template data 2025-03-04 15:20:23 -08:00
Marcus Moore
cb5b0bd89c Stop reporting report template creates, updates, and deletes to action log 2025-03-04 15:11:37 -08:00
snipe
0ed49fa7a0 Dev assets
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 22:55:58 +00:00
snipe
f25b8379e6 Merge pull request #16413 from Godmartinz/visited_link-color-change
Changed `visited-link` and `link` colors in default theme to be more accessible
2025-03-04 22:55:17 +00:00
snipe
bc618fcef4 Merge pull request #16414 from Godmartinz/Audit_error_fix
Adds audit notification for MS Teams
2025-03-04 22:54:32 +00:00
Godfrey M
7c194422f3 Merge branch 'develop' into Audit_error_fix 2025-03-04 14:51:21 -08:00
Godfrey M
49ff47fbcf Merge branch 'develop' into visited_link-color-change 2025-03-04 14:47:48 -08:00
snipe
cc73b984cb Merge remote-tracking branch 'origin/develop' 2025-03-04 21:13:43 +00:00
snipe
77c978d29a Merge pull request #16416 from Godmartinz/expiring-asset-email-test
fix Expiring alert tests
2025-03-04 21:11:52 +00:00
Godfrey M
437b3cd865 fix conflicts 2025-03-04 13:08:53 -08:00
Godfrey M
3641016271 remove commented code 2025-03-04 13:08:03 -08:00
Godfrey Martinez
cc127c8e1e Merge branch 'develop' into expiring-asset-email-test 2025-03-04 13:06:36 -08:00
Godfrey M
4bac509341 fix Expiring alert tests 2025-03-04 12:58:04 -08:00
snipe
f4f6dcb885 Updated test
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 20:48:59 +00:00
snipe
d89f38bbfb Set defaults on save
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 20:38:33 +00:00
snipe
9351cc2252 Set default to 0
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 20:38:22 +00:00
snipe
a31a732d38 Nicer UI for invert flag
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 20:38:15 +00:00
snipe
1be420b0e9 Fixed test
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 20:37:45 +00:00
snipe
548ef97c32 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-03-04 19:57:33 +00:00
snipe
2b0127ab0c Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 19:56:58 +00:00
snipe
ed8a486726 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:54:08 +00:00
snipe
8791640908 Add @Fiala06 as a contributor 2025-03-04 19:53:25 +00:00
snipe
1ab0911fc8 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:52:16 +00:00
snipe
1dacd25e6d Check for purchase_cost before adding the “each”
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 19:50:11 +00:00
snipe
bdbaea7294 Merge remote-tracking branch 'origin/develop' 2025-03-04 19:43:28 +00:00
snipe
45317c0959 Merge pull request #16415 from snipe/nicer_error_message_on_model_not_found
Nicer model name formatting on RMB model not found
2025-03-04 19:42:45 +00:00
snipe
63e4c42445 Added strtolower
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 19:33:17 +00:00
snipe
d4e227f003 Whitespace
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 19:29:09 +00:00
snipe
bbabbe1b87 Nicer model name formatting on RMB model not found
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 19:21:46 +00:00
Marcus Moore
2a156776a4 Merge branch 'develop' into chore/migrate-select-helper
# Conflicts:
#	resources/views/settings/branding.blade.php
#	resources/views/settings/general.blade.php
2025-03-04 11:19:38 -08:00
Godfrey M
15a09e5187 adds audit notification for MS Teams 2025-03-04 11:15:03 -08:00
Godfrey M
5eebdcddb2 changes visited and link colors 2025-03-04 10:12:45 -08:00
snipe
5cfd1f6fb2 Merge remote-tracking branch 'origin/develop' 2025-03-04 17:16:26 +00:00
snipe
16b97c18e0 Shim route for asset maintenances redirect on RMB not found
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 17:16:16 +00:00
snipe
5eda67381f Merge remote-tracking branch 'origin/develop' 2025-03-04 17:07:13 +00:00
snipe
fa72696a35 Removed redundent text
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 17:06:56 +00:00
snipe
2c8b8bfaf2 Merge remote-tracking branch 'origin/develop' 2025-03-04 17:05:55 +00:00
snipe
9467ec2571 Nicer env text
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 17:05:45 +00:00
snipe
8f3159751a Merge remote-tracking branch 'origin/develop' 2025-03-04 17:01:07 +00:00
snipe
ac3f61c96a Fixed extra escape character
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 17:00:44 +00:00
snipe
4b05e55b29 Merge remote-tracking branch 'origin/develop' 2025-03-04 15:56:05 +00:00
snipe
d2e0a23994 Merge pull request #16412 from snipe/#16150_fixed_regression_in_branding_page
Fixed regression from #16150
2025-03-04 15:55:24 +00:00
snipe
ccea55308b Fixed regression from #16150
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 15:53:30 +00:00
snipe
3d3c13fcd0 Merge remote-tracking branch 'origin/develop' 2025-03-04 15:38:58 +00:00
snipe
acaa3a28e7 Merge pull request #16410 from snipe/#16407_component_checkout_and_notes_fix
Fixed #16407 - weird layout on components for non super user
2025-03-04 15:38:20 +00:00
snipe
c4722898b7 Fixed #16407 - weird layout on components for non super user
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 15:37:25 +00:00
snipe
88e1d8a8cf Merge remote-tracking branch 'origin/develop' 2025-03-04 15:28:53 +00:00
snipe
e19003aea5 Merge pull request #16409 from snipe/#16386_user_dropdown_fields_not_populating_on_edit
Fixed #16386 - some fields not populating with user data on edit
2025-03-04 15:28:11 +00:00
snipe
a09a9d3cd6 Added item to payload
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 15:26:25 +00:00
snipe
759e3794df Small upgrader UI fixes
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 14:57:28 +00:00
snipe
c50b14763f Merge pull request #16403 from snipe/#16402_each_localization
Fixed #16402 - localize "each" string in components tab on asset view
2025-03-04 13:35:08 +00:00
snipe
369a68fe57 Fixed #16402 - Localize “each” in string
Signed-off-by: snipe <snipe@snipe.net>
2025-03-04 13:33:04 +00:00
snipe
83855d44d0 Merge pull request #16251 from Godmartinz/Audit_Checkin_warning_fix
refactors audit notification to mail, adds test, adds  alerts check to scheduler
2025-03-04 12:51:42 +00:00
snipe
6f847294ed Merge pull request #15911 from Fiala06/patch-1
Fixed duplicate entries preventing LDAP sync from continuing
2025-03-04 12:49:54 +00:00
snipe
d556d1c6e7 Merge pull request #16150 from Godmartinz/add-translations-to-settings
Adds Translation strings to General and Branding Settings
2025-03-04 12:48:21 +00:00
snipe
3bb94e98f0 Merge pull request #16398 from marcusmoore/bug/sc-28535
Avoid using authenticated user's email address in email partial
2025-03-04 12:47:10 +00:00
Marcus Moore
8f5f6f3502 Avoid using authenticated user's email address in email partial 2025-03-03 16:28:08 -08:00
snipe
e007db34e2 Merge remote-tracking branch 'origin/develop' 2025-03-03 22:12:26 +00:00
snipe
b3792bfa00 Merge pull request #16396 from marcusmoore/chore/migrate-checkbox-helpers-pt10
Replace calls to Form::checkbox pt10
2025-03-03 20:52:54 +00:00
Marcus Moore
40f7257723 Replace call to Form::checkbox 2025-03-03 12:44:50 -08:00
snipe
8486256142 Merge pull request #16381 from marcusmoore/chore/migrate-checkbox-helpers-pt9
Replace calls to Form::checkbox pt9
2025-03-03 20:28:21 +00:00
snipe
7f36750e33 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2025-03-03 19:54:14 +00:00
snipe
de046db106 Add @azmcnutt as a contributor 2025-03-03 19:53:30 +00:00
snipe
eb1d27a5bc Merge pull request #16379 from azmcnutt/feature/settings_ldap_invert_active_flag
Feature/settings ldap invert active flag
2025-03-03 19:52:57 +00:00
Godfrey M
cc0b9f404a merged develop, fix conflicts 2025-02-27 15:38:31 -08:00
Marcus Moore
70332696c6 Fix test by passing in required properties 2025-02-27 15:23:17 -08:00
Marcus Moore
7a9b5d61b0 Replace another Form::checkbox 2025-02-27 13:25:32 -08:00
Marcus Moore
5876259893 Replace another Form::checkbox 2025-02-27 13:19:26 -08:00
Marcus Moore
8755c54edc Replace Form::checkbox 2025-02-27 13:13:39 -08:00
Marcus Moore
014f3b7652 Cast to boolean 2025-02-27 13:12:01 -08:00
Marcus Moore
3a2579b205 WIP: replace Form::checkbox 2025-02-27 13:08:02 -08:00
James M
149474bfe3 Update general.php
FIX: Spelling error
2025-02-27 12:42:47 -07:00
James M
b2b768dede Merge branch 'snipe:develop' into develop 2025-02-27 12:25:07 -07:00
snipe
f9f06d2c02 Merge remote-tracking branch 'origin/develop' 2025-02-27 19:08:45 +00:00
snipe
a9ed9e2a7f Merge pull request #16378 from snipe/wrap_pdf_table_results
Wrap long text in PDF export in tables
2025-02-27 19:06:34 +00:00
snipe
ce8523b00a Fixed wrapping
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 18:58:18 +00:00
snipe
7076a68d35 Wrap table results in PDF
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 18:38:10 +00:00
James M
112112d258 Feat: #14926 LDAP Active Flag - Add config option to make False = Enable 2025-02-27 10:52:12 -07:00
snipe
3928c8afe9 Merge pull request #16376 from uberbrady/improve_safety_csv_charset_detection
Add some safeties around the charset-detection and transliteration
2025-02-27 16:26:44 +00:00
snipe
234f7d00c8 Merge remote-tracking branch 'origin/develop' 2025-02-27 16:18:18 +00:00
snipe
23ce54e80c Make sure we’re saving the last_login in 2FA auths
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 16:17:59 +00:00
Brady Wetherington
646e3e8df5 Complete failed-transliteration test, clean up error, new translation string 2025-02-27 16:10:56 +00:00
snipe
30c4e9dbf7 Use formatter for created_at on unaccepted assets
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 15:48:24 +00:00
snipe
9924553da5 Merge remote-tracking branch 'origin/develop' 2025-02-27 15:45:57 +00:00
snipe
27fc30a881 Nicer button layout on unaccepted assets
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 15:43:53 +00:00
snipe
8ac7cda4ee Merge pull request #16366 from marcusmoore/chore/migrate-checkbox-helpers-pt7
Replace calls to Form::checkbox pt7
2025-02-27 15:01:31 +00:00
snipe
6f04d314a8 Merge pull request #16367 from marcusmoore/chore/migrate-checkbox-helpers-pt8
Replace calls to Form::checkbox pt8
2025-02-27 15:01:19 +00:00
snipe
1051b1d16d Merge pull request #16375 from snipe/fixes_16371_name_not_included_in_reminder_emails
Fixed #16371 - incorrect count and missing name in acceptance reminder email
2025-02-27 15:00:04 +00:00
snipe
115bb94704 Merge pull request #16156 from marcusmoore/acceptance-reminder-subject
Added "Reminder" to subject line of follow up asset checkout emails
2025-02-27 14:55:59 +00:00
snipe
25807cc62f Fixed constructor
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 14:22:48 +00:00
snipe
cd1d1b2d3e Fixed count
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 14:22:40 +00:00
Brady Wetherington
6dcd3bfd30 Add some safeties around the charset-detection and transliteration 2025-02-27 13:44:31 +00:00
snipe
df38d7e3ed Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	config/version.php
2025-02-27 12:22:30 +00:00
snipe
b8799f8038 Bumped bash
Signed-off-by: snipe <snipe@snipe.net>
2025-02-27 12:21:28 +00:00
Marcus Moore
a0dc056da8 Replace Form::checkbox on label settings page 2025-02-26 16:33:07 -08:00
Marcus Moore
27aeb518ff Replace Form::checkbox on general settings page 2025-02-26 16:18:00 -08:00
snipe
dc619bb0dc Merge pull request #16365 from marcusmoore/chore/migrate-checkbox-helpers-pt6
Replace calls to Form::checkbox pt6
2025-02-26 23:54:50 +00:00
Marcus Moore
245a16c377 Replace Form::checkbox on branding settings page 2025-02-26 15:37:07 -08:00
Marcus Moore
de3c1d159f Replace Form::checkbox on branding settings page 2025-02-26 15:35:17 -08:00
Marcus Moore
af6d9e4a00 Replace Form::checkbox on custom report pages 2025-02-26 15:15:48 -08:00
snipe
8c8af3062e Merge pull request #16354 from snipe/dont_checkin_for_pending_on_asset_update
Allow pending as an asset status type that does not automatically check the asset in
2025-02-26 21:05:11 +00:00
snipe
44dd061619 Merge remote-tracking branch 'origin/develop' 2025-02-26 20:55:57 +00:00
snipe
2ff47edb94 Merge pull request #16361 from Godmartinz/acceptancer_reminder_unlisted_email_info
Fixed acceptance reminder command lag on users with no associated email
2025-02-26 20:33:02 +00:00
snipe
d923d29bad Merge pull request #16360 from spencerrlongg/bug/sc-28537
Add Safety Around Bulk Status Update
2025-02-26 20:32:19 +00:00
Godfrey M
899119ae2d changes output to a table 2025-02-26 12:30:19 -08:00
snipe
7603a932b1 Merge remote-tracking branch 'origin/develop' 2025-02-26 20:29:42 +00:00
snipe
e031de8e49 Merge pull request #16363 from snipe/added_a_few_more_no_interaction_calls
Added `--no-interaction` to additional passport commands
2025-02-26 20:19:37 +00:00
snipe
a81c520d93 Follow up for #16341
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 20:15:09 +00:00
Godfrey M
8352e81228 fix unaccepted reminder test 2025-02-26 11:50:08 -08:00
Godfrey M
fd0174ff32 remove unwanted changes to livewire 2025-02-26 11:31:41 -08:00
Godfrey M
cc26aa02b2 fix acceptance reminder command no email list 2025-02-26 11:25:21 -08:00
snipe
616f3558dd Update example env
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 19:14:25 +00:00
spencerrlongg
d6e266cec1 make super safe 2025-02-26 13:11:49 -06:00
snipe
138e7acc13 Merge remote-tracking branch 'origin/develop' 2025-02-26 12:47:54 +00:00
snipe
31516d7f24 Merge pull request #16356 from snipe/added_fields_for_model_search
Added name, model_number and notes for strict search
2025-02-26 12:46:13 +00:00
snipe
e79af255aa Added name, model_number and notes for strict search
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 12:43:54 +00:00
snipe
e863d3e7e5 Merge remote-tracking branch 'origin/develop' 2025-02-26 12:02:00 +00:00
snipe
5b0d7f4064 One more chonk
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 12:01:50 +00:00
snipe
c8e401f5ed Merge remote-tracking branch 'origin/develop' 2025-02-26 11:59:53 +00:00
snipe
2f6af10c5d Bumped chunk for custom report
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 11:59:34 +00:00
snipe
3ba20a8e28 Merge remote-tracking branch 'origin/develop' 2025-02-26 11:39:10 +00:00
snipe
afabda9235 Remove greater than 0 for alert threshold - fixes FD-47040
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 11:38:33 +00:00
snipe
1618c9ae8e Changed confirmation message
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:53:41 +00:00
snipe
5344ef4a1a Allow pending as an asset status that does not automatically check the asset in
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:46:38 +00:00
snipe
ebae63752f Merge remote-tracking branch 'origin/develop' 2025-02-26 10:25:18 +00:00
snipe
16420b1e00 Audit Log Number under Days to next Audit [sc-28530]
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 10:25:07 +00:00
snipe
62f66e724e Drop errors to warnings to stop pooping on rollbar
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 09:54:13 +00:00
snipe
9b0ea51d35 Moved composer clear commands to after composer install per #16334
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 09:37:31 +00:00
snipe
8bc73901cf Merge remote-tracking branch 'origin/develop' 2025-02-26 08:25:35 +00:00
snipe
992214fc66 Check for adminuser withTrashed
Signed-off-by: snipe <snipe@snipe.net>
2025-02-26 08:25:22 +00:00
snipe
b4f70d9244 Merge remote-tracking branch 'origin/develop' 2025-02-26 07:16:59 +00:00
snipe
93dab12461 Merge pull request #16342 from snipe/nicer_upgrade_script
Nicer upgrade.php UI
2025-02-26 07:16:28 +00:00
snipe
21e9f2bba3 Merge remote-tracking branch 'origin/develop' 2025-02-26 07:11:22 +00:00
snipe
ea0f105180 Merge pull request #16347 from marcusmoore/chore/migrate-checkbox-helpers-pt4
Replace calls to Form::checkbox pt4
2025-02-26 07:05:38 +00:00
snipe
5b6da0c1e8 Merge pull request #16348 from marcusmoore/chore/migrate-checkbox-helpers-pt5
Replace calls to Form::checkbox pt5
2025-02-26 07:05:22 +00:00
snipe
4d7655bbe1 Merge pull request #16346 from marcusmoore/chore/migrate-checkbox-helpers-pt3
Replace calls to Form::checkbox pt3
2025-02-26 07:04:27 +00:00
snipe
5e3855ee5b Merge pull request #16345 from marcusmoore/fixes/update-custom-fields
Fixed renaming custom fields
2025-02-26 07:03:40 +00:00
Marcus Moore
e01226a174 Replace Form::checkbox on saml settings page 2025-02-25 17:31:05 -08:00
Marcus Moore
f9ccf32af4 Replace Form::checkbox on ldap settings page 2025-02-25 17:22:44 -08:00
Marcus Moore
2c5170a218 Replace Form::checkbox on security settings page 2025-02-25 17:09:25 -08:00
Marcus Moore
15f842e2dc Replace Form::checkbox on bulk user edit page 2025-02-25 16:00:46 -08:00
Marcus Moore
46b31dfe14 Replace Form::checkbox on user create and edit page 2025-02-25 14:32:39 -08:00
Marcus Moore
d88c79366c Replace Form::checkbox on google settings page 2025-02-25 14:27:07 -08:00
Marcus Moore
de330a47cd Replace Form::checkbox on asset tag settings page 2025-02-25 14:25:02 -08:00
Marcus Moore
ecd7dc2094 Replace Form::checkbox on alert settings page 2025-02-25 14:23:26 -08:00
Marcus Moore
510946e0eb Replace Form::checkbox in logo upload partial 2025-02-25 14:20:43 -08:00
Marcus Moore
37e4a13979 Replace Form::checkbox in image upload partial 2025-02-25 14:15:12 -08:00
Marcus Moore
c73d64cdbc Remove manual doctrine mapping for enums 2025-02-25 13:37:23 -08:00
snipe
4a0410d969 Uncomment git stash
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:55:39 +00:00
snipe
668b9f8fb9 Nicer upgrade.php UI
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 16:51:32 +00:00
snipe
037d2d9e84 Merge pull request #16341 from uberbrady/fix_passport_install_no_interaction
Fixes #16331 - Don't make passport:install command require user input
2025-02-25 16:43:49 +00:00
Brady Wetherington
bce2007b97 Fixes #16331 - Don't make passport:install command require user input 2025-02-25 16:38:40 +00:00
snipe
881f4e3d6a Merge remote-tracking branch 'origin/develop' 2025-02-25 14:43:57 +00:00
Brady Wetherington
09a5e5b1bd Whoops! Need minimum 8.2, not 8.1 (probably mis-merge?) 2025-02-25 14:40:45 +00:00
snipe
7b4f4b6b7f Merge pull request #16337 from joakimbergros/develop
Fixed #16173: `useraccountcontrol` was not included in the ldap query attributes
2025-02-25 13:49:38 +00:00
Joakim Bergros
5c66334017 Added a check to see if the user has specified that is an ActiveDirectory server in the configuration before adding the useraccountcontrol attribute to the ldap query. 2025-02-25 14:22:22 +01:00
Joakim Bergros
ae82051b73 Fixed #16173: useraccountcontrol was not included in the ldap query attributes.
`$results` did not include the `useraccountcontrol` and thus rendered the fallback logic void when `active_flag` was blank.

 Added a condition to check if `active_flag` is blank and only then add `useraccountcontrol` to the ldap query since it is then a requirement in accordance with "we respect the userAccountControl attribute" text in the `admin/ldap` route.

[`elseif' will become true when `active_flag` is blank](b141945add/app/Console/Commands/LdapSync.php (L364))
2025-02-25 13:55:53 +01:00
snipe
b141945add Updated branch
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:18:52 +00:00
snipe
c3a2e81afd Updated version
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:18:22 +00:00
snipe
18c7cbbbbb Merge pull request #16336 from snipe/change_order_in_upgrade_script
Fixed #16334 - Changed composer order in upgrade script
2025-02-25 12:09:15 +00:00
snipe
3718f08c72 Changed composer order in upgrade script
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 12:05:00 +00:00
snipe
b7821a69b6 Added link to the google apps script repo
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 11:07:04 +00:00
snipe
8049f21068 Updated laravel version in readme
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 11:02:00 +00:00
snipe
8140110bf9 Chnage dev docker env to en-US from en
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 10:57:38 +00:00
snipe
a4587f6322 Merge pull request #16335 from snipe/added_label_test
Added label test
2025-02-25 10:40:46 +00:00
snipe
163e19f1e9 Added label test
Signed-off-by: snipe <snipe@snipe.net>
2025-02-25 10:37:06 +00:00
snipe
8a40c3ecb4 Merge pull request #16325 from spencerrlongg/bug/sc-28520
Remove remaining hardware references in favor of new RMB
2025-02-25 10:09:35 +00:00
spencerrlongg
d949a9689f fix all 2025-02-24 22:35:47 -06:00
snipe
27a7c6fd10 Merge pull request #16324 from marcusmoore/chore/migrate-checkbox-helpers-p2
Replace calls to Form::checkbox pt2
2025-02-25 02:33:02 +00:00
Marcus Moore
4d55a67628 Merge branch 'develop' into chore/migrate-checkbox-helpers-p2 2025-02-24 16:37:59 -08:00
snipe
9d453226bd Merge pull request #16321 from spencerrlongg/bug/sc-28515
Changed Parameter Name for RMB
2025-02-25 00:17:37 +00:00
snipe
cd26694767 Merge pull request #16322 from marcusmoore/fixes/fix-test-edit-route
Fixed edit routes in tests
2025-02-25 00:17:10 +00:00
Marcus Moore
a26cc2ced1 Use .edit routes instead of .update 2025-02-24 15:55:05 -08:00
spencerrlongg
1fd81d17a3 route model binding change 2025-02-24 17:53:41 -06:00
snipe
134045f1ec Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2025-02-24 23:46:55 +00:00
snipe
b6b6a3eec7 Remove req for 0 min
Signed-off-by: snipe <snipe@snipe.net>
2025-02-24 23:46:50 +00:00
snipe
b62714d702 Merge pull request #16062 from snipe/remove_mcrypt
Removed references to mcrypt
2025-02-24 23:22:32 +00:00
Brady Wetherington
271bcc66bf Remove lib-mcrypt as a dependency 2025-02-24 23:19:08 +00:00
snipe
ced560daa9 Add @jostrander as a contributor 2025-02-24 23:16:27 +00:00
snipe
b395c9130a Merge remote-tracking branch 'origin/master' into develop 2025-02-24 23:06:46 +00:00
snipe
ed46a757fa Merge pull request #16320 from jostrander/fix/location-edit
Fixed: fix 500 on edit locations page by referencing current location
2025-02-24 23:03:01 +00:00
Jesse Ostrander
6a8a41b389 fix: reference to item location on location edit method 2025-02-24 17:34:18 -05:00
snipe
4800f4c853 Merge branch 'develop' into remove_mcrypt 2025-02-24 22:12:56 +00:00
snipe
c79ff49c85 Add @addex12 as a contributor 2025-02-24 20:30:04 +00:00
Marcus Moore
e88bba51bb Merge branch 'develop' into acceptance-reminder-subject 2025-02-24 11:55:50 -08:00
Marcus Moore
f97211f6cd Remove unused language string 2025-02-24 11:45:58 -08:00
Marcus Moore
027c2b3627 Change subject to "You have Unaccepted Assets." 2025-02-24 11:45:23 -08:00
snipe
5ece721b00 Check for FMCS
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 15:02:45 +00:00
snipe
0e2251c810 Scope selectlist by company
Signed-off-by: snipe <snipe@snipe.net>
2025-02-23 14:59:05 +00:00
Godfrey M
4c43a06eee add overdue asset to test 2025-02-13 11:19:49 -08:00
Godfrey M
25c8449e86 remove unused 2025-02-13 11:14:18 -08:00
Godfrey M
13e1f4a127 adds mailable 2025-02-13 11:09:39 -08:00
Godfrey M
ed96fd766c refactors audit notification to mail, adds test, ads check to scheduler 2025-02-13 11:08:53 -08:00
Marcus Moore
00e7795414 Merge branch 'develop' into chore/migrate-select-helper
# Conflicts:
#	resources/views/partials/forms/edit/company.blade.php
2025-02-10 15:44:02 -08:00
Marcus Moore
77635c3737 Migrate Form::checkboxes on license edit view 2025-02-06 17:05:35 -08:00
Marcus Moore
b937b7e767 Migrate Form::checkboxes on asset history import page 2025-02-06 17:01:09 -08:00
Marcus Moore
7cbb3f7e07 Add assertion 2025-01-30 11:48:55 -08:00
Marcus Moore
7e9c564d0b Simplify test 2025-01-30 11:47:43 -08:00
Marcus Moore
fc88b2487f Extract method 2025-01-30 11:44:37 -08:00
Marcus Moore
e94ee48f74 Extract helper 2025-01-30 10:37:11 -08:00
Marcus Moore
6a4a5d1380 Add translation 2025-01-30 10:35:31 -08:00
Marcus Moore
ab9e9b66d2 Reduce complexity 2025-01-29 16:27:18 -08:00
Marcus Moore
c15c338ffd Merge if/else 2025-01-29 16:25:37 -08:00
Marcus Moore
d1197d015c Add another case scenario 2025-01-29 16:24:43 -08:00
Marcus Moore
ce31ce477e Inline additional variables 2025-01-29 16:16:47 -08:00
Marcus Moore
78f9292555 Inline variable 2025-01-29 16:15:27 -08:00
Marcus Moore
4e7c6bd2cf Fix relationship 2025-01-29 16:14:09 -08:00
Marcus Moore
70aed45bfe Improve naming 2025-01-29 15:56:20 -08:00
Marcus Moore
e2805f4033 Add "Reminder" to subject line 2025-01-29 15:36:45 -08:00
Marcus Moore
d254a40e0a Scaffold tests 2025-01-29 15:21:10 -08:00
Marcus Moore
fdcb891cbb Improve test case 2025-01-29 15:20:56 -08:00
Godfrey M
16d322d70e fix translation 2025-01-29 10:38:30 -08:00
Godfrey M
2163312997 adds translations for branding and general settings 2025-01-29 10:35:26 -08:00
Godfrey M
0dfb71cfe5 added some translations to branding and general setrting 2025-01-28 11:56:10 -08:00
Tobias Regnery
4e0bcac1a1 Furhter validation for scoped locations
There is a new validator introduced that checks on object update (assets, users, etc.) if the company matches the locations company.
In case of the creation of a new location it must be checked that the parent matches the own company.
On updating a location a check for every related object must be made to see if the company matches the location.

Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
2025-01-24 11:12:11 +01:00
Tobias Regnery
6921df9334 Check for inconsistencies before activating scoped locations
Before activating scoped location all locations and their related objects will be checked.
If there are locations with different companies than the related objects error out.

Because this operation is quite slow, bail out on the first inconsistent entry.
There is a new artisan command introduced that checks every location.

Depending on the size of the database, this will take very long.

Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
2025-01-23 15:26:04 +01:00
snipe
b6f05bff1f Merge branch 'develop' into feature/locations_with_companies 2025-01-17 17:18:17 +00:00
Marcus Moore
abb50fcd09 Delete unused partials 2025-01-13 16:21:19 -08:00
Marcus Moore
3fadeebd82 Convert additional Form::select to blade component 2025-01-13 16:20:02 -08:00
Marcus Moore
9a043da005 Convert additional Form::select to blade component 2025-01-13 16:16:49 -08:00
Marcus Moore
3eb307a019 Convert additional Form::select to blade component 2025-01-13 15:58:15 -08:00
Marcus Moore
888c96718c Convert additional Form::select to blade component 2025-01-13 15:38:51 -08:00
Marcus Moore
bc3f236b86 Weaken comparsion so string and int keys match 2025-01-13 15:38:45 -08:00
Marcus Moore
1f4cc0a4b4 Convert additional Form::select to blade component 2025-01-13 15:23:43 -08:00
Marcus Moore
589ec3a564 Convert additional Form::select to blade component 2025-01-13 13:08:59 -08:00
Marcus Moore
2206b0a699 Convert additional Form::select to blade component 2025-01-13 12:50:18 -08:00
Marcus Moore
d74454620a Convert Form::select to blade component 2025-01-13 12:45:49 -08:00
Marcus Moore
ed0cec5ba6 Introduce select component 2025-01-13 12:17:01 -08:00
snipe
99526cfc2c Remove mcrypt and legacy recrypter
Signed-off-by: snipe <snipe@snipe.net>
2025-01-13 19:54:00 +00:00
spencerrlongg
513c78a09f Refactor CheckoutRequest actions for consistency
Renamed CheckoutRequest action classes to include "Action" in their names for consistency and clarity. Enhanced error handling in controllers to standardize error responses with translations. Updated usage of the renamed action classes throughout the code to ensure proper integration.
2024-12-03 17:51:12 -06:00
spencerrlongg
0103f20193 Merge branch 'develop' into feature/sc-24347 2024-12-03 16:05:39 -06:00
Fiala06
bdb0e6c2a3 Update LdapSync.php
Fix for duplicate entries preventing the sync from continuing. 

  SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '13178-6' for key 'PRIMARY' (Connection: mysql, SQL: insert into users_groups (group_id, user_id) values (6, 13178))
2024-12-02 11:07:37 -08:00
Brady Wetherington
eccdcc373e parent 2220828b00
author Brady Wetherington <bwetherington@grokability.com> 1728320853 +0100
committer Brady Wetherington <bwetherington@grokability.com> 1733158021 +0000

Prevent setting assigned_to without setting assigned_type

Fixed tests to include assigned_type when setting assigned_to

Add new tests for assigned_to without assigned_type

Added tighter validation to assigned_to and assigned_type, new tests

Fixed wrong comment

Fixed tests to include assigned_type when setting assigned_to

Add new tests for assigned_to without assigned_type

Fixed wrong comment
2024-12-02 16:53:08 +00:00
Tobias Regnery
651d1c735b Another slightly less ugly way for backward compatibility
Instead of using a constructor, add a special check in the boot-method for locations.
This seems to fit better in the system and does hopefully not break the existing tests.

Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
2024-11-04 10:03:38 +01:00
Tobias Regnery
1318dc6111 Add a backward compatibility setting for locations with companies
Now that locations have a company_id they get restricted to the users company with FullMultipleCompanySupport.
This breaks backward compatibility, because before everyone can handle locations without restrictions.
Add a setting right below FullMultipleCompanySupport so that everyone can switch to the desired behaviour.
The default is off and the existing behaviour is preserved.
2024-11-04 10:03:38 +01:00
Tobias Regnery
1ccbf8942c Add ability to tie locations to companies
Locations are the last big part of the application that can't be tied to companies.
This can be a problem with FullMultipleCompanySupport, because you can't restrict the visibility of locations to the company of the users.

In order to change this, add a company_id to the locations table and wire everything up in the views and controllers.
Aditionally add a new formatter to filter the locations to a specific company, like it is done for assets.

Locations are properly scoped to the users company if FullMultipleCompanySupport is enabled.
If a parent location of a location has a different company than the user, the location does not show up.
2024-11-04 10:03:37 +01:00
spencerrlongg
c76cccbb68 rm extraneous methods in exception 2024-10-23 12:56:36 -05:00
spencerrlongg
fdb6970f36 this is pretty much done 2024-10-23 01:41:27 -05:00
spencerrlongg
b0d7eb2168 cancel action finished 2024-10-22 22:44:28 -05:00
spencerrlongg
79e6eafafa cancelled scaffolded out 2024-10-22 22:33:29 -05:00
spencerrlongg
3ee008e871 revert 2024-10-22 20:54:20 -05:00
spencerrlongg
48c812d345 bunch of cleanup, split cancel out 2024-10-22 20:48:27 -05:00
spencerrlongg
8a99cc1391 test working 2024-10-22 17:25:58 -05:00
spencerrlongg
b59bf495e1 stuff 2024-10-22 15:09:35 -05:00
spencerrlongg
e40849c910 this stuff works 2024-10-21 17:31:26 -05:00
spencerrlongg
95a32864cf hm, lots to think about 🤔 2024-10-17 18:11:18 -05:00
spencerrlongg
1fd945c2d8 this works 2024-10-17 12:45:49 -05:00
spencerrlongg
b2ff34260a hm, lots of thinking to do 2024-10-17 00:02:15 -05:00
spencerrlongg
a524c0b418 more work 2024-10-16 18:48:15 -05:00
spencerrlongg
b1d62cc478 initial untested 2024-10-16 17:23:22 -05:00
snipe
5cdb52a249 Corrected flag
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 21:33:08 +01:00
snipe
ea38d6c2f3 Decode as integers
Signed-off-by: snipe <snipe@snipe.net>
2024-08-29 21:26:38 +01:00
1837 changed files with 31469 additions and 283243 deletions

View File

@@ -2590,10 +2590,10 @@
]
},
{
"login": "QveenSi",
"login": "qveensi",
"name": "Yevhenii Huzii",
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
"profile": "https://github.com/QveenSi",
"profile": "https://github.com/qveensi",
"contributions": [
"code"
]
@@ -2607,15 +2607,6 @@
"code"
]
},
{
"login": "QveenSi",
"name": "Yevhenii Huzii",
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
"profile": "https://github.com/QveenSi",
"contributions": [
"code"
]
},
{
"login": "chrisweirich",
"name": "Christian Weirich",
@@ -3271,6 +3262,897 @@
"contributions": [
"code"
]
},
{
"login": "addex12",
"name": "Adugna Gizaw",
"avatar_url": "https://avatars.githubusercontent.com/u/18550946?v=4",
"profile": "https://orbalia.pythonanywhere.com/",
"contributions": [
"translation"
]
},
{
"login": "jostrander",
"name": "Jesse Ostrander",
"avatar_url": "https://avatars.githubusercontent.com/u/760989?v=4",
"profile": "https://github.com/jostrander",
"contributions": [
"code"
]
},
{
"login": "azmcnutt",
"name": "James M",
"avatar_url": "https://avatars.githubusercontent.com/u/31522486?v=4",
"profile": "https://github.com/azmcnutt",
"contributions": [
"code"
]
},
{
"login": "Fiala06",
"name": "Fiala06",
"avatar_url": "https://avatars.githubusercontent.com/u/5183146?v=4",
"profile": "https://github.com/Fiala06",
"contributions": [
"code"
]
},
{
"login": "ntaylor-86",
"name": "Nathan Taylor",
"avatar_url": "https://avatars.githubusercontent.com/u/28693782?v=4",
"profile": "https://github.com/ntaylor-86",
"contributions": [
"code"
]
},
{
"login": "fvollmer",
"name": "fvollmer",
"avatar_url": "https://avatars.githubusercontent.com/u/16699443?v=4",
"profile": "https://github.com/fvollmer",
"contributions": [
"code"
]
},
{
"login": "36864",
"name": "36864",
"avatar_url": "https://avatars.githubusercontent.com/u/109086466?v=4",
"profile": "https://github.com/36864",
"contributions": [
"code"
]
},
{
"login": "CloCkWeRX",
"name": "Daniel O'Connor",
"avatar_url": "https://avatars.githubusercontent.com/u/365751?v=4",
"profile": "http://clockwerx.blogspot.com/",
"contributions": [
"code"
]
},
{
"login": "BeatSpark",
"name": "BeatSpark",
"avatar_url": "https://avatars.githubusercontent.com/u/102852568?v=4",
"profile": "https://github.com/BeatSpark",
"contributions": [
"code"
]
},
{
"login": "mrdahbi",
"name": "mrdahbi",
"avatar_url": "https://avatars.githubusercontent.com/u/59203607?v=4",
"profile": "https://github.com/mrdahbi",
"contributions": [
"code"
]
},
{
"login": "chfsx",
"name": "Fabian Schmid",
"avatar_url": "https://avatars.githubusercontent.com/u/6661332?v=4",
"profile": "http://sr.solutions",
"contributions": [
"code"
]
},
{
"login": "realchrisolin",
"name": "Chris Olin",
"avatar_url": "https://avatars.githubusercontent.com/u/1288116?v=4",
"profile": "https://www.chrisolin.com",
"contributions": [
"code"
]
},
{
"login": "mnemonicly",
"name": "Dan",
"avatar_url": "https://avatars.githubusercontent.com/u/3803132?v=4",
"profile": "https://github.com/mnemonicly",
"contributions": [
"code"
]
},
{
"login": "NebelKreis",
"name": "Nebel",
"avatar_url": "https://avatars.githubusercontent.com/u/43917728?v=4",
"profile": "https://github.com/NebelKreis",
"contributions": [
"code"
]
},
{
"login": "test1337ahp",
"name": "test1337ahp",
"avatar_url": "https://avatars.githubusercontent.com/u/132433803?v=4",
"profile": "https://github.com/test1337ahp",
"contributions": [
"code"
]
},
{
"login": "JonathonReinhart",
"name": "Jonathon Reinhart",
"avatar_url": "https://avatars.githubusercontent.com/u/1916566?v=4",
"profile": "https://github.com/JonathonReinhart",
"contributions": [
"code"
]
},
{
"login": "aranar-pro",
"name": "aranar-pro",
"avatar_url": "https://avatars.githubusercontent.com/u/484742?v=4",
"profile": "https://github.com/aranar-pro",
"contributions": [
"code"
]
},
{
"login": "phil-flip",
"name": "Phil",
"avatar_url": "https://avatars.githubusercontent.com/u/27019397?v=4",
"profile": "https://github.com/phil-flip",
"contributions": [
"code"
]
},
{
"login": "fe80",
"name": "Steffy Fort",
"avatar_url": "https://avatars.githubusercontent.com/u/6473460?v=4",
"profile": "https://fe80.fr/",
"contributions": [
"code"
]
},
{
"login": "sorvani",
"name": "Jared Busch",
"avatar_url": "https://avatars.githubusercontent.com/u/3302372?v=4",
"profile": "https://github.com/sorvani",
"contributions": [
"code"
]
},
{
"login": "seanborg-codethink",
"name": "seanborg-codethink",
"avatar_url": "https://avatars.githubusercontent.com/u/111956991?v=4",
"profile": "https://github.com/seanborg-codethink",
"contributions": [
"code"
]
},
{
"login": "dkaatz",
"name": "dkaatz",
"avatar_url": "https://avatars.githubusercontent.com/u/160669961?v=4",
"profile": "https://github.com/dkaatz",
"contributions": [
"code"
]
},
{
"login": "DanielRuf",
"name": "Daniel Ruf",
"avatar_url": "https://avatars.githubusercontent.com/u/827205?v=4",
"profile": "https://threema.id/74SF7MW6?text=",
"contributions": [
"code"
]
},
{
"login": "ahpaleus",
"name": "ahpaleus",
"avatar_url": "https://avatars.githubusercontent.com/u/38883201?v=4",
"profile": "https://github.com/ahpaleus",
"contributions": [
"code"
]
},
{
"login": "mink-adao-duy",
"name": "Anh DAO-DUY",
"avatar_url": "https://avatars.githubusercontent.com/u/22906055?v=4",
"profile": "https://github.com/mink-adao-duy",
"contributions": [
"code"
]
},
{
"login": "Serdnad",
"name": "Andres Gutierrez",
"avatar_url": "https://avatars.githubusercontent.com/u/4723453?v=4",
"profile": "https://github.com/Serdnad",
"contributions": [
"code"
]
},
{
"login": "wewhite",
"name": "Warren White",
"avatar_url": "https://avatars.githubusercontent.com/u/111083379?v=4",
"profile": "https://github.com/wewhite",
"contributions": [
"code"
]
},
{
"login": "robintemme",
"name": "Robin Temme",
"avatar_url": "https://avatars.githubusercontent.com/u/2809241?v=4",
"profile": "https://robintemme.de/",
"contributions": [
"code"
]
},
{
"login": "herroworrd",
"name": "herroworrd",
"avatar_url": "https://avatars.githubusercontent.com/u/47008367?v=4",
"profile": "https://github.com/herroworrd",
"contributions": [
"code"
]
},
{
"login": "vicleos",
"name": "vicleos",
"avatar_url": "https://avatars.githubusercontent.com/u/28558609?v=4",
"profile": "https://mubiu.com/",
"contributions": [
"code"
]
},
{
"login": "thinkl33t",
"name": "Bob Clough",
"avatar_url": "https://avatars.githubusercontent.com/u/1016780?v=4",
"profile": "http://thinkl33t.co.uk/",
"contributions": [
"code"
]
},
{
"login": "brandon-bailey",
"name": "Brandon Daniel Bailey",
"avatar_url": "https://avatars.githubusercontent.com/u/10648463?v=4",
"profile": "https://github.com/brandon-bailey",
"contributions": [
"code"
]
},
{
"login": "marcquark",
"name": "Marc Bartelt",
"avatar_url": "https://avatars.githubusercontent.com/u/23556080?v=4",
"profile": "https://github.com/marcquark",
"contributions": [
"code"
]
},
{
"login": "manu-crealytics",
"name": "manu-crealytics",
"avatar_url": "https://avatars.githubusercontent.com/u/18286893?v=4",
"profile": "https://github.com/manu-crealytics",
"contributions": [
"code"
]
},
{
"login": "Galaxy102",
"name": "Konstantin Köhring",
"avatar_url": "https://avatars.githubusercontent.com/u/18245993?v=4",
"profile": "https://www.galaxy102.de/",
"contributions": [
"code"
]
},
{
"login": "deloz",
"name": "Deloz",
"avatar_url": "https://avatars.githubusercontent.com/u/685167?v=4",
"profile": "https://deloz.net/",
"contributions": [
"code"
]
},
{
"login": "mbrrg",
"name": "Martin Berg",
"avatar_url": "https://avatars.githubusercontent.com/u/2682426?v=4",
"profile": "https://github.com/mbrrg",
"contributions": [
"code"
]
},
{
"login": "Nothing4You",
"name": "Richard Schwab",
"avatar_url": "https://avatars.githubusercontent.com/u/3694534?v=4",
"profile": "https://github.com/Nothing4You",
"contributions": [
"code"
]
},
{
"login": "rickheil",
"name": "Rick Heil",
"avatar_url": "https://avatars.githubusercontent.com/u/8959676?v=4",
"profile": "https://rickheil.com/",
"contributions": [
"code"
]
},
{
"login": "rosscdh",
"name": "Ross Crawford-d'Heureuse",
"avatar_url": "https://avatars.githubusercontent.com/u/397106?v=4",
"profile": "https://github.com/rosscdh",
"contributions": [
"code"
]
},
{
"login": "McG800",
"name": "Ryan McGuire",
"avatar_url": "https://avatars.githubusercontent.com/u/1621107?v=4",
"profile": "https://github.com/McG800",
"contributions": [
"code"
]
},
{
"login": "SBrown2021",
"name": "SBrown2021",
"avatar_url": "https://avatars.githubusercontent.com/u/77835667?v=4",
"profile": "https://github.com/SBrown2021",
"contributions": [
"code"
]
},
{
"login": "serkanerip",
"name": "Serkan",
"avatar_url": "https://avatars.githubusercontent.com/u/8780913?v=4",
"profile": "https://github.com/serkanerip",
"contributions": [
"code"
]
},
{
"login": "Shankschn",
"name": "Shanks",
"avatar_url": "https://avatars.githubusercontent.com/u/63188620?v=4",
"profile": "https://www.yudelei.com/",
"contributions": [
"code"
]
},
{
"login": "cendai-mis",
"name": "cendai-mis",
"avatar_url": "https://avatars.githubusercontent.com/u/198525698?v=4",
"profile": "https://github.com/cendai-mis",
"contributions": [
"code"
]
},
{
"login": "smcpeck",
"name": "Shaun McPeck",
"avatar_url": "https://avatars.githubusercontent.com/u/8724583?v=4",
"profile": "https://smcpeck.github.io/",
"contributions": [
"code"
]
},
{
"login": "snazy2000",
"name": "Stephen",
"avatar_url": "https://avatars.githubusercontent.com/u/1378836?v=4",
"profile": "https://github.com/snazy2000",
"contributions": [
"code"
]
},
{
"login": "Nevets82",
"name": "Steven",
"avatar_url": "https://avatars.githubusercontent.com/u/4462739?v=4",
"profile": "http://nevets82.github.io/",
"contributions": [
"code"
]
},
{
"login": "Mateus-Romera",
"name": "Mateus Villar",
"avatar_url": "https://avatars.githubusercontent.com/u/29017267?v=4",
"profile": "https://mateusvillar.com/",
"contributions": [
"code"
]
},
{
"login": "mzack5020",
"name": "Matthew Zackschewski",
"avatar_url": "https://avatars.githubusercontent.com/u/12749393?v=4",
"profile": "https://github.com/mzack5020",
"contributions": [
"code"
]
},
{
"login": "firefrei",
"name": "Matthias Frei",
"avatar_url": "https://avatars.githubusercontent.com/u/12660103?v=4",
"profile": "https://www.frei.media/",
"contributions": [
"code"
]
},
{
"login": "nticaric",
"name": "Nenad Ticaric",
"avatar_url": "https://avatars.githubusercontent.com/u/824840?v=4",
"profile": "https://github.com/nticaric",
"contributions": [
"code"
]
},
{
"login": "Scorcher",
"name": "Nikolay Didenko",
"avatar_url": "https://avatars.githubusercontent.com/u/706439?v=4",
"profile": "https://github.com/Scorcher",
"contributions": [
"code"
]
},
{
"login": "nunomaduro",
"name": "Nuno Maduro",
"avatar_url": "https://avatars.githubusercontent.com/u/5457236?v=4",
"profile": "https://nunomaduro.com/sponsorships",
"contributions": [
"code"
]
},
{
"login": "owalerys",
"name": "Oliver Walerys",
"avatar_url": "https://avatars.githubusercontent.com/u/8883074?v=4",
"profile": "https://tektikhq.com/",
"contributions": [
"code"
]
},
{
"login": "rcmcdonald91",
"name": "R. Christian McDonald",
"avatar_url": "https://avatars.githubusercontent.com/u/3102039?v=4",
"profile": "https://keybase.io/rcmcdonald91",
"contributions": [
"code"
]
},
{
"login": "nixn",
"name": "nix",
"avatar_url": "https://avatars.githubusercontent.com/u/1525581?v=4",
"profile": "https://nnix.net/",
"contributions": [
"code"
]
},
{
"login": "octobunny",
"name": "octobunny",
"avatar_url": "https://avatars.githubusercontent.com/u/55462380?v=4",
"profile": "https://github.com/octobunny",
"contributions": [
"code"
]
},
{
"login": "sreyemnayr",
"name": "Ryan",
"avatar_url": "https://avatars.githubusercontent.com/u/8558670?v=4",
"profile": "https://github.com/sreyemnayr",
"contributions": [
"code"
]
},
{
"login": "p3nj",
"name": "p3nj",
"avatar_url": "https://avatars.githubusercontent.com/u/1501022?v=4",
"profile": "https://benji.ltd/",
"contributions": [
"code"
]
},
{
"login": "timwsuqld",
"name": "Tim White",
"avatar_url": "https://avatars.githubusercontent.com/u/6201617?v=4",
"profile": "https://github.com/timwsuqld",
"contributions": [
"code"
]
},
{
"login": "yannikp",
"name": "yannikp",
"avatar_url": "https://avatars.githubusercontent.com/u/22473767?v=4",
"profile": "https://github.com/yannikp",
"contributions": [
"code"
]
},
{
"login": "viclou",
"name": "victoria",
"avatar_url": "https://avatars.githubusercontent.com/u/20525448?v=4",
"profile": "https://github.com/viclou",
"contributions": [
"code"
]
},
{
"login": "valentyntu",
"name": "Valentyn Tulub",
"avatar_url": "https://avatars.githubusercontent.com/u/40685314?v=4",
"profile": "https://github.com/valentyntu",
"contributions": [
"code"
]
},
{
"login": "Wouter0100",
"name": "Wouter van Os",
"avatar_url": "https://avatars.githubusercontent.com/u/864520?v=4",
"profile": "http://wouter0100.nl/",
"contributions": [
"code"
]
},
{
"login": "xWyatt",
"name": "Wyatt Teeter",
"avatar_url": "https://avatars.githubusercontent.com/u/3946540?v=4",
"profile": "https://www.linkedin.com/in/wyatt-teeter",
"contributions": [
"code"
]
},
{
"login": "terwey",
"name": "Yorick Terweijden",
"avatar_url": "https://avatars.githubusercontent.com/u/1596124?v=4",
"profile": "https://github.com/terwey",
"contributions": [
"code"
]
},
{
"login": "bmkalle",
"name": "bmkalle",
"avatar_url": "https://avatars.githubusercontent.com/u/69298836?v=4",
"profile": "https://github.com/bmkalle",
"contributions": [
"code"
]
},
{
"login": "bricelabelle",
"name": "bricelabelle",
"avatar_url": "https://avatars.githubusercontent.com/u/28403467?v=4",
"profile": "https://github.com/bricelabelle",
"contributions": [
"code"
]
},
{
"login": "corydlamb",
"name": "corydlamb",
"avatar_url": "https://avatars.githubusercontent.com/u/97770090?v=4",
"profile": "https://github.com/corydlamb",
"contributions": [
"code"
]
},
{
"login": "splashx",
"name": "Diogenes S. Jesus",
"avatar_url": "https://avatars.githubusercontent.com/u/1154133?v=4",
"profile": "http://twitter.com/splash",
"contributions": [
"code"
]
},
{
"login": "dkmansion",
"name": "D M",
"avatar_url": "https://avatars.githubusercontent.com/u/5826629?v=4",
"profile": "https://github.com/dkmansion",
"contributions": [
"code"
]
},
{
"login": "Jarli01",
"name": "Dustin B",
"avatar_url": "https://avatars.githubusercontent.com/u/14837699?v=4",
"profile": "https://github.com/Jarli01",
"contributions": [
"code"
]
},
{
"login": "fabiang",
"name": "Fabian Grutschus",
"avatar_url": "https://avatars.githubusercontent.com/u/348344?v=4",
"profile": "https://github.com/fabiang",
"contributions": [
"code"
]
},
{
"login": "MelonSmasher",
"name": "MelonSmasher",
"avatar_url": "https://avatars.githubusercontent.com/u/1491053?v=4",
"profile": "https://github.com/MelonSmasher",
"contributions": [
"code"
]
},
{
"login": "AlexanderWPapyrus",
"name": "AlexanderWPapyrus",
"avatar_url": "https://avatars.githubusercontent.com/u/80526133?v=4",
"profile": "https://github.com/AlexanderWPapyrus",
"contributions": [
"code"
]
},
{
"login": "disc",
"name": "Alexandr Hacicheant",
"avatar_url": "https://avatars.githubusercontent.com/u/306231?v=4",
"profile": "https://github.com/disc",
"contributions": [
"code"
]
},
{
"login": "hex128",
"name": "Hex",
"avatar_url": "https://avatars.githubusercontent.com/u/3032891?v=4",
"profile": "https://hex128.io/",
"contributions": [
"code"
]
},
{
"login": "arukompas",
"name": "Arunas Skirius",
"avatar_url": "https://avatars.githubusercontent.com/u/8697942?v=4",
"profile": "https://github.com/arukompas",
"contributions": [
"code"
]
},
{
"login": "benperiton",
"name": "Ben Periton",
"avatar_url": "https://avatars.githubusercontent.com/u/104396?v=4",
"profile": "https://github.com/benperiton",
"contributions": [
"code"
]
},
{
"login": "byronwolfman",
"name": "Byron Wolfman",
"avatar_url": "https://avatars.githubusercontent.com/u/11906832?v=4",
"profile": "https://wolfman.dev/",
"contributions": [
"code"
]
},
{
"login": "CalvinSchwartz",
"name": "Calvin",
"avatar_url": "https://avatars.githubusercontent.com/u/56485508?v=4",
"profile": "https://github.com/CalvinSchwartz",
"contributions": [
"code"
]
},
{
"login": "juanfont",
"name": "Juan Font",
"avatar_url": "https://avatars.githubusercontent.com/u/181059?v=4",
"profile": "https://github.com/juanfont",
"contributions": [
"code"
]
},
{
"login": "juhotaipale",
"name": "Juho Taipale",
"avatar_url": "https://avatars.githubusercontent.com/u/13137708?v=4",
"profile": "https://github.com/juhotaipale",
"contributions": [
"code"
]
},
{
"login": "KorvinSzanto",
"name": "Korvin Szanto",
"avatar_url": "https://avatars.githubusercontent.com/u/1007419?v=4",
"profile": "https://github.com/KorvinSzanto",
"contributions": [
"code"
]
},
{
"login": "sniff122",
"name": "Lewis Foster",
"avatar_url": "https://avatars.githubusercontent.com/u/8513053?v=4",
"profile": "https://lewisfoster.foo/",
"contributions": [
"code"
]
},
{
"login": "loganswartz",
"name": "Logan Swartzendruber",
"avatar_url": "https://avatars.githubusercontent.com/u/33877541?v=4",
"profile": "https://github.com/loganswartz",
"contributions": [
"code"
]
},
{
"login": "lopezio",
"name": "Lorenzo P.",
"avatar_url": "https://avatars.githubusercontent.com/u/1156208?v=4",
"profile": "https://github.com/lopezio",
"contributions": [
"code"
]
},
{
"login": "m4us1ne",
"name": "Lukas Jung",
"avatar_url": "https://avatars.githubusercontent.com/u/33946590?v=4",
"profile": "https://github.com/m4us1ne",
"contributions": [
"code"
]
},
{
"login": "LeafedFox",
"name": "Ellie",
"avatar_url": "https://avatars.githubusercontent.com/u/10965027?v=4",
"profile": "https://leafedfox.xyz/",
"contributions": [
"code"
]
},
{
"login": "gastamper",
"name": "GA Stamper",
"avatar_url": "https://avatars.githubusercontent.com/u/20960555?v=4",
"profile": "https://github.com/gastamper",
"contributions": [
"code"
]
},
{
"login": "gl-pup",
"name": "Guillaume Lefranc",
"avatar_url": "https://avatars.githubusercontent.com/u/206553556?v=4",
"profile": "https://github.com/gl-pup",
"contributions": [
"code"
]
},
{
"login": "dasjoe",
"name": "Hajo Möller",
"avatar_url": "https://avatars.githubusercontent.com/u/733892?v=4",
"profile": "https://github.com/dasjoe",
"contributions": [
"code"
]
},
{
"login": "pottom",
"name": "Istvan Basa",
"avatar_url": "https://avatars.githubusercontent.com/u/3420063?v=4",
"profile": "https://github.com/pottom",
"contributions": [
"code"
]
},
{
"login": "jjasghar",
"name": "JJ Asghar",
"avatar_url": "https://avatars.githubusercontent.com/u/810824?v=4",
"profile": "https://jjasghar.github.io/",
"contributions": [
"code"
]
},
{
"login": "JemCdo",
"name": "James E. Msenga",
"avatar_url": "https://avatars.githubusercontent.com/u/40404495?v=4",
"profile": "https://github.com/JemCdo",
"contributions": [
"code"
]
},
{
"login": "jfwiebe",
"name": "Jan Felix Wiebe",
"avatar_url": "https://avatars.githubusercontent.com/u/6865786?v=4",
"profile": "https://github.com/jfwiebe",
"contributions": [
"code"
]
},
{
"login": "drexljo",
"name": "Jo Drexl",
"avatar_url": "https://avatars.githubusercontent.com/u/43412008?v=4",
"profile": "https://www.nfon.com/",
"contributions": [
"code"
]
},
{
"login": "austinsasko",
"name": "Austin Sasko",
"avatar_url": "https://avatars.githubusercontent.com/u/4807843?v=4",
"profile": "https://github.com/austinsasko",
"contributions": [
"code"
]
}
]
}

View File

@@ -16,7 +16,7 @@ APP_DEBUG=true
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
APP_URL=http://localhost:8000
APP_TIMEZONE='UTC'
APP_LOCALE=en
APP_LOCALE=en-US
MAX_RESULTS=500
# --------------------------------------------
@@ -35,6 +35,7 @@ DB_USERNAME=snipeit
DB_PASSWORD=changeme1234
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_DUMP_SKIP_SSL=true
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
@@ -78,6 +79,13 @@ MAIL_BACKUP_NOTIFICATION_DRIVER=null
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
BACKUP_ENV=true
# --------------------------------------------
# OPTIONAL: CHANGE PHP UPLOAD LIMITS (UNCOMMENT WHEN NEEDING TO BE CHANGED)
# --------------------------------------------
#PHP_UPLOAD_LIMIT=10
#PHP_POST_MAX_SIZE=10
#PHP_UPLOAD_MAX_FILESIZE=10
#PHP_MEMORY_LIMIT=10
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS

View File

@@ -35,6 +35,7 @@ DB_PASSWORD=changeme1234
MYSQL_ROOT_PASSWORD=changeme1234
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_DUMP_SKIP_SSL=true
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
@@ -83,6 +84,15 @@ MAIL_BACKUP_NOTIFICATION_DRIVER=null
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
BACKUP_ENV=true
# --------------------------------------------
# OPTIONAL: CHANGE PHP UPLOAD LIMITS (UNCOMMENT WHEN NEEDING TO BE CHANGED)
# --------------------------------------------
#PHP_UPLOAD_LIMIT=10
#PHP_POST_MAX_SIZE=10
#PHP_UPLOAD_MAX_FILESIZE=10
#PHP_MEMORY_LIMIT=10
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------

View File

@@ -30,6 +30,7 @@ DB_USERNAME=null
DB_PASSWORD=null
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_DUMP_SKIP_SSL=false
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_SANITIZE_BY_DEFAULT=false
@@ -99,7 +100,7 @@ PASSPORT_COOKIE_NAME='snipeit_passport_token'
COOKIE_DOMAIN=null
SECURE_COOKIES=false
API_TOKEN_EXPIRATION_YEARS=15
BS_TABLE_STORAGE=cookieStorage
BS_TABLE_STORAGE=localStorage
BS_TABLE_DEEPLINK=true
# --------------------------------------------
@@ -178,6 +179,7 @@ PASSWORD_RESET_MAX_ATTEMPTS_PER_MIN=50
# OPTIONAL: MISC
# --------------------------------------------
LOG_CHANNEL=single
LOG_DEPRECATIONS=false
LOG_MAX_DAYS=10
APP_LOCKED=false
APP_CIPHER=AES-256-CBC

View File

@@ -22,11 +22,11 @@ permissions:
jobs:
codacy-security-scan:
# Ensure schedule job never runs on forked repos. It's only executed for 'snipe/snipe-it'
# Ensure schedule job never runs on forked repos. It's only executed for 'grokability/snipe-it'
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
if: (github.repository == 'snipe/snipe-it') || ((github.repository != 'snipe/snipe-it') && (github.event_name != 'schedule'))
if: (github.repository == 'grokability/snipe-it') || ((github.repository != 'grokability/snipe-it') && (github.event_name != 'schedule'))
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:

View File

@@ -20,8 +20,8 @@ permissions:
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
if: github.repository == 'snipe/snipe-it'
# Ensure this job never runs on forked repos. It's only executed for 'grokability/snipe-it'
if: github.repository == 'grokability/snipe-it'
runs-on: ubuntu-latest
env:
# Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
@@ -32,7 +32,7 @@ jobs:
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
type=ref,event=tag,suffix=-alpine
type=semver,pattern=v{{major}}-latest-alpine
type=semver,pattern=v{{major}}-latest-alpine
# Define default tag "flavor" for docker/metadata-action per
# https://github.com/docker/metadata-action#flavor-input
# We turn off 'latest' tag by default.

View File

@@ -1,5 +1,5 @@
# Snipe-IT Docker image build for hub.docker.com
name: Docker images
name: Docker images (Ubuntu)
# Run this Build for all pushes to 'master' or develop branch, or tagged releases.
# Also run for PRs to ensure PR doesn't break Docker build process
@@ -20,8 +20,8 @@ permissions:
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
if: github.repository == 'snipe/snipe-it'
# Ensure this job never runs on forked repos. It's only executed for 'grokability/snipe-it'
if: github.repository == 'grokability/snipe-it'
runs-on: ubuntu-latest
env:
# Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
@@ -32,7 +32,7 @@ jobs:
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=tag
type=semver,pattern=v{{major}}-latest
type=semver,pattern=v{{major}}-latest
# Define default tag "flavor" for docker/metadata-action per
# https://github.com/docker/metadata-action#flavor-input
# We turn off 'latest' tag by default.

View File

@@ -67,7 +67,7 @@ jobs:
run: |
php artisan key:generate
php artisan migrate --force
php artisan passport:install
php artisan passport:install --no-interaction
chmod -R 777 storage bootstrap/cache
- name: Execute tests (Unit and Feature tests) via PHPUnit

View File

@@ -65,7 +65,7 @@ jobs:
run: |
php artisan key:generate
php artisan migrate --force
php artisan passport:install
php artisan passport:install --no-interaction
chmod -R 777 storage bootstrap/cache
- name: Execute tests (Unit and Feature tests) via PHPUnit

240
.pa11yci.json Normal file
View File

@@ -0,0 +1,240 @@
{
"standard": "WCAG2AA",
"level": "error",
"defaults": {
"useIncognitoBrowserContext": false,
"timeout": 500000,
"wait": 5000,
"ignore" : [
"WCAG2AA.Principle1.Guideline1_4.1_4_3.G145.Fail",
"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail"
],
"viewport": {
"width": 1280,
"height": 1024
}
},
"urls": [
{
"__NOTE" : "this should always be FIRST (if browser context is preserved)",
"url": "https://snipe-it.test/login",
"actions": [
"navigate to https://snipe-it.test/login",
"screen capture tests/pa11y/login.png",
"set field input[name='username'] to admin",
"set field input[name='password'] to password",
"click element button[type=submit]",
"wait for url to be https://snipe-it.test/",
"screen capture tests/pa11y/dashboard.png"
]
},
{
"url" : "https://snipe-it.test/admin",
"actions" : [
"navigate to https://snipe-it.test/admin",
"screen capture tests/pa11y/admin-settings.png"
]
},
{
"url" : "https://snipe-it.test/admin/branding",
"actions" : [
"navigate to https://snipe-it.test/admin/branding",
"screen capture tests/pa11y/admin-branding.png"
]
},
{
"url" : "https://snipe-it.test/admin/general",
"actions" : [
"navigate to https://snipe-it.test/admin/general",
"screen capture tests/pa11y/admin-general.png"
]
},
{
"url" : "https://snipe-it.test/hardware/create",
"actions" : [
"navigate to https://snipe-it.test/hardware/create",
"screen capture tests/pa11y/asset-create.png"
]
},
{
"url" : "https://snipe-it.test/hardware",
"actions" : [
"navigate to https://snipe-it.test/hardware",
"screen capture tests/pa11y/asset-list.png"
]
},
{
"url" : "https://snipe-it.test/hardware/1",
"actions" : [
"navigate to https://snipe-it.test/hardware/1",
"screen capture tests/pa11y/asset-detail.png"
]
},
{
"url" : "https://snipe-it.test/account/view-assets",
"actions" : [
"navigate to https://snipe-it.test/account/view-assets",
"screen capture tests/pa11y/profile.png"
]
},
{
"url" : "https://snipe-it.test/licences",
"actions" : [
"navigate to https://snipe-it.test/licenses",
"screen capture tests/pa11y/license-list.png"
]
},
{
"url" : "https://snipe-it.test/licences/create",
"actions" : [
"navigate to https://snipe-it.test/licenses/create",
"screen capture tests/pa11y/license-create.png"
]
},
{
"url" : "https://snipe-it.test/licences/1",
"actions" : [
"navigate to https://snipe-it.test/licenses/1",
"screen capture tests/pa11y/license-view.png"
]
},
{
"url" : "https://snipe-it.test/consumables",
"actions" : [
"navigate to https://snipe-it.test/consumables",
"screen capture tests/pa11y/consumable-list.png"
]
},
{
"url" : "https://snipe-it.test/consumables/create",
"actions" : [
"navigate to https://snipe-it.test/consumables/create",
"screen capture tests/pa11y/consumable-create.png"
]
},
{
"url" : "https://snipe-it.test/consumables/1",
"actions" : [
"navigate to https://snipe-it.test/consumables/1",
"screen capture tests/pa11y/consumable-view.png"
]
},
{
"url" : "https://snipe-it.test/accessories",
"actions" : [
"navigate to https://snipe-it.test/accessories",
"screen capture tests/pa11y/accessory-list.png"
]
},
{
"url" : "https://snipe-it.test/accessories/create",
"actions" : [
"navigate to https://snipe-it.test/accessories/create",
"screen capture tests/pa11y/accessory-create.png"
]
},
{
"url" : "https://snipe-it.test/accessories/1",
"actions" : [
"navigate to https://snipe-it.test/accessories/1",
"screen capture tests/pa11y/accessory-view.png"
]
},
{
"url" : "https://snipe-it.test/locations",
"actions" : [
"navigate to https://snipe-it.test/locations",
"screen capture tests/pa11y/location-list.png"
]
},
{
"url" : "https://snipe-it.test/locations/create",
"actions" : [
"navigate to https://snipe-it.test/locations/create",
"screen capture tests/pa11y/location-create.png"
]
},
{
"url" : "https://snipe-it.test/locations/1",
"actions" : [
"navigate to https://snipe-it.test/locations/1",
"screen capture tests/pa11y/location-view.png"
]
},
{
"url" : "https://snipe-it.test/models",
"actions" : [
"navigate to https://snipe-it.test/models",
"screen capture tests/pa11y/model-list.png"
]
},
{
"url" : "https://snipe-it.test/models/create",
"actions" : [
"navigate to https://snipe-it.test/models/create",
"screen capture tests/pa11y/model-create.png"
]
},
{
"url" : "https://snipe-it.test/models/1",
"actions" : [
"navigate to https://snipe-it.test/models/1",
"screen capture tests/pa11y/model-view.png"
]
},
{
"url" : "https://snipe-it.test/companies",
"actions" : [
"navigate to https://snipe-it.test/companies",
"screen capture tests/pa11y/company-list.png"
]
},
{
"url" : "https://snipe-it.test/companies/create",
"actions" : [
"navigate to https://snipe-it.test/companies/create",
"screen capture tests/pa11y/company-create.png"
]
},
{
"url" : "https://snipe-it.test/companies/1",
"actions" : [
"navigate to https://snipe-it.test/companies/1",
"screen capture tests/pa11y/company-view.png"
]
},
{
"url" : "https://snipe-it.test/departments",
"actions" : [
"navigate to https://snipe-it.test/departments",
"screen capture tests/pa11y/department-list.png"
]
},
{
"url" : "https://snipe-it.test/departments/create",
"actions" : [
"navigate to https://snipe-it.test/departments/create",
"screen capture tests/pa11y/department-create.png"
]
},
{
"url" : "https://snipe-it.test/departments/1",
"actions" : [
"navigate to https://snipe-it.test/departments/1",
"screen capture tests/pa11y/department-view.png"
]
},
{
"url" : "https://snipe-it.test/invalid-url",
"actions" : [
"navigate to https://snipe-it.test/invalid-url",
"screen capture tests/pa11y/404.png"
]
}
]
}

View File

@@ -3,7 +3,7 @@
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
"DOC4": "You should really just ignore it and run upgrade.php. Really",
"php_min_version": "8.1.0",
"php_min_version": "8.2.0",
"php_max_major_minor": "8.4",
"php_max_wontwork": "8.5.0",
"current_snipeit_version": "8.0"

View File

@@ -1,59 +1,606 @@
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 -->
| [<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") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<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)") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<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") |
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") |
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") | [<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") | [<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") | [<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") | [<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") | [<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") | [<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") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
| [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") |
| [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") |
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<tr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</tr>
<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 -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -2,7 +2,7 @@ FROM ubuntu:24.04
LABEL maintainer="Brady Wetherington <bwetherington@grokability.com>"
# No need to add `apt-get clean` here, reference:
# - https://github.com/snipe/snipe-it/pull/9201
# - https://github.com/grokability/snipe-it/pull/9201
# - https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#apt-get
RUN export DEBIAN_FRONTEND=noninteractive; \
@@ -40,7 +40,6 @@ autoconf \
libc-dev \
libldap-common \
pkg-config \
libmcrypt-dev \
php8.3-dev \
ca-certificates \
unzip \
@@ -51,11 +50,6 @@ dnsutils \
RUN curl -L -O https://github.com/pear/pearweb_phars/raw/master/go-pear.phar
RUN php go-pear.phar
RUN pecl install mcrypt
RUN bash -c "echo extension=/usr/lib/php/20210902/mcrypt.so > /etc/php/8.3/mods-available/mcrypt.ini"
RUN phpenmod mcrypt
RUN phpenmod gd
RUN phpenmod bcmath
@@ -116,7 +110,7 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Get dependencies
USER docker
RUN composer install --no-dev --working-dir=/var/www/html
RUN COMPOSER_CACHE_DIR=/dev/null composer install --no-dev --working-dir=/var/www/html && rm -rf /var/www/html/vendor/*/*/.git
USER root
############### APPLICATION INSTALL/INIT #################

View File

@@ -70,7 +70,7 @@ COPY --from=composer /usr/bin/composer /usr/local/bin
ARG COMPOSER_ALLOW_SUPERUSER=1
RUN set -eux; \
# Download and extract snipeit tarball
curl -o snipeit.tar.gz -fL "https://github.com/snipe/snipe-it/archive/v$SNIPEIT_RELEASE.tar.gz"; \
curl -o snipeit.tar.gz -fL "https://github.com/grokability/snipe-it/archive/v$SNIPEIT_RELEASE.tar.gz"; \
tar -xzf snipeit.tar.gz --strip-components=1 -C /var/www/html/; \
rm snipeit.tar.gz; \
# Install composer php dependencies

View File

@@ -1,15 +1,15 @@
![snipe-it-by-grok](https://github.com/snipe/snipe-it/assets/197404/b515673b-c7c8-4d9a-80f5-9fa58829a602)
![snipe-it-by-grok](https://github.com/grokability/snipe-it/assets/197404/b515673b-c7c8-4d9a-80f5-9fa58829a602)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://app.codacy.com/gh/snipe/snipe-it/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Tests](https://github.com/snipe/snipe-it/actions/workflows/tests.yml/badge.svg)](https://github.com/snipe/snipe-it/actions/workflows/tests.yml)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://app.codacy.com/gh/snipe/snipe-it/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Tests](https://github.com/grokability/snipe-it/actions/workflows/tests.yml/badge.svg)](https://github.com/grokability/snipe-it/actions/workflows/tests.yml)
[![All Contributors](https://img.shields.io/badge/all_contributors-331-orange.svg?style=flat-square)](#contributing) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk)
## Snipe-IT - Open Source Asset Management System
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
It is built on [Laravel 10](http://laravel.com).
It is built on [Laravel 11](http://laravel.com).
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
Snipe-IT is actively developed and we [release quite frequently](https://github.com/grokability/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
> [!TIP]
> __This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, any flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
@@ -44,7 +44,7 @@ For help using Snipe-IT, check out the [user's manual](https://snipe-it.readme.i
-----
### Bug Reports & Feature Requests
Feel free to check out the [GitHub Issues for this project](https://github.com/snipe/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open *and* closed) to see if your question has already been answered before opening a new issue.
Feel free to check out the [GitHub Issues for this project](https://github.com/grokability/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open *and* closed) to see if your question has already been answered before opening a new issue.
> [!IMPORTANT]
> **PLEASE see the [Getting Help Guidelines](https://snipe-it.readme.io/docs/getting-help) and [Common Issues](https://snipe-it.readme.io/docs/common-issues) before opening a ticket, and be sure to complete all of the questions in the Github Issue template to help us to help you as quickly as possible.**
@@ -76,23 +76,36 @@ Since the release of the JSON REST API, several third-party developers have been
> [!NOTE]
> As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
#### Libraries & Modules
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
- [jamf-snipe-rename](https://macblog.org/jamf-snipe-rename/) - Python script to rename computers in Jamf from Snipe-IT
- [Marksman](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-IT.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT.
- [WWW::SnipeIT](https://github.com/SEDC/perl-www-snipeit) by [@SEDC](https://github.com/SEDC) - perl module for accessing the API
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
- [UniFi to Snipe-IT](https://www.edtechirl.com/p/snipe-it-and-azure-asset-management) originally by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by [@ReticentRobot](https://github.com/ReticentRobot) - Windows agent for Snipe-IT.
- [Gate Pass Generator](https://github.com/cha7uraAE/snipe-it-gate-pass-system) by [@cha7uraAE](https://github.com/cha7uraAE) - A Streamlit application for generating gate passes based on hardware data from a Snipe-IT API.
- [InQRy (archived)](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [Marksman (archived)](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
- [Python Module (archived)](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
We also have a handful of [Google Apps scripts](https://github.com/grokability/google-apps-scripts-for-snipe-it) to help with various tasks.
#### Mobile Apps
We're currently working on our own mobile app, but in the meantime, check out these third-party apps that work with Snipe-IT:
- [SnipeMate](https://snipemate.app/) (iOS, Google Play, Huawei AppGallery) by Mars Technology
- [Snipe-Scan](https://apps.apple.com/do/app/snipe-scan/id6744179400?uo=2) (iOS) by Nicolas Maton
- [Snipe-IT Assets Management](https://play.google.com/store/apps/details?id=com.diegogarciadev.assetsmanager.snipeit&hl=en&pli=1) (Google Play) by DiegoGarciaDEV
- [AssetX](https://apps.apple.com/my/app/assetx-for-snipe-it/id6741996196?uo=2) (iOS) for Snipe-IT by Rishi Gupta
-----
@@ -120,9 +133,15 @@ The ERD is available [online here](https://drawsql.app/templates/snipe-it).
Be sure to check out all of the [amazing people](CONTRIBUTORS.md) that have contributed to Snipe-IT over the years!
-----
### Star History
[![Star History Chart](https://api.star-history.com/svg?repos=grokability/snipe-it&type=Date)](https://www.star-history.com/#grokability/snipe-it&Date)
------
### Announcement List
To be notified of important news (such as new releases, security advisories, etc), [sign up for our list](http://eepurl.com/XyZKz). We'll never sell or give away your info, and we'll only email you when it's important.
To be notified of important news (such as new releases, security advisories, etc), [sign up for our list](http://eepurl.com/XyZKz). We'll never sell or give away your info, and we'll only email you when it's important.
We also usually make smaller announcements on our social accounts, our Discord, and our blog, so be sure to subscribe to those if you're looking for more granular announcements.

View File

@@ -11,6 +11,7 @@ make it impossible to backport security fixes on older versions.
| Version | Supported |
|---------| ------------------ |
| 8.x | :white_check_mark: |
| 7.x | :white_check_mark: |
| 6.x | :x: |
| 5.1.x | :x: |

2
Vagrantfile vendored
View File

@@ -1,7 +1,7 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
SNIPEIT_SH_URL= "https://raw.githubusercontent.com/snipe/snipe-it/master/snipeit.sh"
SNIPEIT_SH_URL= "https://raw.githubusercontent.com/grokability/snipe-it/master/snipeit.sh"
NETWORK_BRIDGE= "en0: Wi-Fi (AirPort)"
Vagrant.configure("2") do |config|

View File

@@ -6,7 +6,7 @@
"it asset"
],
"website": "https://snipeitapp.com/",
"repository": "https://github.com/snipe/snipe-it",
"repository": "https://github.com/grokability/snipe-it",
"logo": "https://pbs.twimg.com/profile_images/976748875733020672/K-HnZCCK_400x400.jpg",
"success_url": "/setup",
"env": {

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Actions\CheckoutRequests;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\RequestAssetCancelation;
use Illuminate\Auth\Access\AuthorizationException;
class CancelCheckoutRequestAction
{
public static function run(Asset $asset, User $user)
{
if (!Company::isCurrentUserHasAccess($asset)) {
throw new AuthorizationException();
}
$asset->cancelRequest();
$asset->decrement('requests_counter', 1);
$data['item'] = $asset;
$data['target'] = $user;
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id;
$logaction->item_type = $data['item_type'] = Asset::class;
$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
$logaction->target_id = $data['user_id'] = auth()->id();
$logaction->target_type = User::class;
$logaction->location_id = $user->location_id ?? null;
$logaction->logaction('request canceled');
try {
$settings->notify(new RequestAssetCancelation($data));
} catch (\Exception $e) {
\Log::warning($e);
}
return true;
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Actions\CheckoutRequests;
use App\Exceptions\AssetNotRequestable;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\RequestAssetNotification;
use Illuminate\Auth\Access\AuthorizationException;
use Log;
class CreateCheckoutRequestAction
{
/**
* @throws AssetNotRequestable
* @throws AuthorizationException
*/
public static function run(Asset $asset, User $user): string
{
if (is_null(Asset::RequestableAssets()->find($asset->id))) {
throw new AssetNotRequestable($asset);
}
if (!Company::isCurrentUserHasAccess($asset)) {
throw new AuthorizationException();
}
$data['item'] = $asset;
$data['target'] = $user;
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id;
$logaction->item_type = $data['item_type'] = Asset::class;
$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
$logaction->target_id = $data['user_id'] = auth()->id();
$logaction->target_type = User::class;
$logaction->location_id = $user->location_id ?? null;
$logaction->logaction('requested');
$asset->request();
$asset->increment('requests_counter', 1);
try {
$settings->notify(new RequestAssetNotification($data));
} catch (\Exception $e) {
Log::warning($e);
}
return true;
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Console\Commands;
use App\Models\Setting;
use Illuminate\Console\Command;
class DisableSAML extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:saml-disable';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This is a rescue command that can be used to turn off SAML settings in the event that you managed to lock yourself out using bad SAML settings.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nThis will disable SAML support. You will not be able \nto login with an account that does not exist \nlocally in the Snipe-IT local database. \n****************************************************\n\nDo you wish to continue? [y|N]")) {
$setting = Setting::getSettings();
$setting->saml_enabled = 0;
if ($setting->save()) {
$this->info('SAML has been set to disabled.');
} else {
$this->info('Unable to disable SAML.');
}
} else {
$this->info('Canceled. No actions taken.');
}
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace App\Console\Commands;
use App\Models\Accessory;
use App\Models\Actionlog;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
class FixBulkAccessoryCheckinActionLogEntries extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:fix-bulk-accessory-action-log-entries {--dry-run : Run the sync process but don\'t update the database} {--skip-backup : Skip pre-execution backup}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This script attempts to fix timestamps and missing created_by values for bulk checkin entries in the log table';
private bool $dryrun = false;
private bool $skipBackup = false;
/**
* Execute the console command.
*/
public function handle()
{
$this->skipBackup = $this->option('skip-backup');
$this->dryrun = $this->option('dry-run');
if ($this->dryrun) {
$this->info('This is a DRY RUN - no changes will be saved.');
$this->newLine();
}
$logs = Actionlog::query()
// only look for accessory checkin logs
->where('item_type', Accessory::class)
// that were part of a bulk checkin
->where('note', 'Bulk checkin items')
// logs that were improperly timestamped should have created_at in the 1970s
->whereYear('created_at', '1970')
->get();
if ($logs->isEmpty()) {
$this->info('No logs found with incorrect timestamps.');
return 0;
}
$this->info('Found ' . $logs->count() . ' logs with incorrect timestamps:');
$this->table(
['ID', 'Created By', 'Created At', 'Updated At'],
$logs->map(function ($log) {
return [
$log->id,
$log->created_by,
$log->created_at,
$log->updated_at,
];
})
);
if (!$this->dryrun && !$this->confirm('Update these logs?')) {
return 0;
}
if (!$this->dryrun && !$this->skipBackup) {
$this->info('Backing up the database before making changes...');
$this->call('snipeit:backup');
}
if ($this->dryrun) {
$this->newLine();
$this->info('DRY RUN. NOT ACTUALLY UPDATING LOGS.');
}
foreach ($logs as $log) {
$this->newLine();
$this->info('Processing log id:' . $log->id);
// created_by was not being set for accessory bulk checkins
// so let's see if there was another bulk checkin log
// with the same timestamp and a created_by value we can use.
if (is_null($log->created_by)) {
$createdByFromSimilarLog = $this->getCreatedByAttributeFromSimilarLog($log);
if ($createdByFromSimilarLog) {
$this->line(vsprintf('Updating log id:%s created_by to %s', [$log->id, $createdByFromSimilarLog]));
$log->created_by = $createdByFromSimilarLog;
} else {
$this->warn(vsprintf('No created_by found for log id:%s', [$log->id]));
$this->warn('Skipping updating this log since no similar log was found to update created_by from.');
// If we can't find a similar log then let's skip updating it
continue;
}
}
$this->line(vsprintf('Updating log id:%s from %s to %s', [$log->id, $log->created_at, $log->updated_at]));
$log->created_at = $log->updated_at;
if (!$this->dryrun) {
Model::withoutTimestamps(function () use ($log) {
$log->saveQuietly();
});
}
}
$this->newLine();
if ($this->dryrun) {
$this->info('DRY RUN. NO CHANGES WERE ACTUALLY MADE.');
}
return 0;
}
/**
* Hopefully the bulk checkin included other items like assets or licenses
* so we can use one of those logs to get the correct created_by value.
*
* This method attempts to find a bulk check in log that was
* created at the same time as the log passed in.
*/
private function getCreatedByAttributeFromSimilarLog(Actionlog $log): null|int
{
$similarLog = Actionlog::query()
->whereNotNull('created_by')
->where([
'action_type' => 'checkin from',
'note' => 'Bulk checkin items',
'target_id' => $log->target_id,
'target_type' => $log->target_type,
'created_at' => $log->updated_at,
])
->first();
if ($similarLog) {
return $similarLog->created_by;
}
return null;
}
}

View File

@@ -2,11 +2,9 @@
namespace App\Console\Commands;
use App\Helpers\Helper;
use Illuminate\Console\Command;
use App\Models\User;
use Laravel\Passport\TokenRepository;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Support\Facades\DB;
class GeneratePersonalAccessToken extends Command
@@ -43,9 +41,8 @@ class GeneratePersonalAccessToken extends Command
*
* @return void
*/
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
public function __construct(TokenRepository $tokenRepository)
{
$this->validation = $validation;
$this->tokenRepository = $tokenRepository;
parent::__construct();
}
@@ -76,7 +73,7 @@ class GeneratePersonalAccessToken extends Command
} else {
$this->warn('Your API Token has been created. Be sure to copy this token now, as it will not be accessible again.');
$this->warn('Your API Token has been created. Be sure to copy this token now, as it WILL NOT be accessible again.');
if ($token = DB::table('oauth_access_tokens')->where('user_id', '=', $user->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first()) {
$this->info('API Token ID: '.$token->id);

View File

@@ -125,6 +125,10 @@ class LdapSync extends Command
*/
$attributes = array_values(array_filter($ldap_map));
if (Setting::getSettings()->is_ad === 1 && is_null($ldap_map['active_flag'])) {
$attributes[] = 'useraccountcontrol';
}
$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);
} catch (\Exception $e) {
@@ -357,9 +361,15 @@ class LdapSync extends Command
// (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_map["active_flag"]][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool) $raw_value;
$user->activated = $filter_var ?? $boolean_cast; // if filter_var() was true or false, use that. If it's null, use the $boolean_cast
if (Setting::getSettings()->ldap_invert_active_flag === 1) {
// Because ldap_active_flag is set, if filter_var is true or boolean_cast is true, then user is suspended
$user->activated = !($filter_var ?? $boolean_cast);
}else{
$user->activated = $filter_var ?? $boolean_cast; // if filter_var() was true or false, use that. If it's null, use the $boolean_cast
}
} elseif (array_key_exists('useraccountcontrol', $results[$i])) {
// ....otherwise, (ie if no 'active' LDAP flag is defined), IF the UAC setting exists,
@@ -424,8 +434,12 @@ class LdapSync extends Command
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
if ($item['createorupdate'] === 'created' && $ldap_default_group) {
$user->groups()->attach($ldap_default_group);
// Check if the relationship already exists
if (!$user->groups()->where('group_id', $ldap_default_group)->exists()) {
$user->groups()->attach($ldap_default_group);
}
}
//updates assets location based on user's location
if ($user->wasChanged('location_id')) {
foreach ($user->assets as $asset) {

View File

@@ -51,8 +51,7 @@ class PaveIt extends Command
}
// List all the tables in the database so we don't have to worry about missing some as the app grows
$tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();
$tables = Schema::getTables();
$except_tables = [
'oauth_access_tokens',
'oauth_clients',
@@ -74,7 +73,8 @@ class PaveIt extends Command
}
}
foreach ($tables as $table) {
foreach ($tables as $table_obj) {
$table = $table_obj['name'];
if (in_array($table, $except_tables)) {
$this->info($table. ' is SKIPPED.');
} else {

View File

@@ -1,157 +0,0 @@
<?php
namespace App\Console\Commands;
use App\LegacyEncrypter\McryptEncrypter;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\Setting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class RecryptFromMcrypt extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:legacy-recrypt
{--force : Force a re-crypt of encrypted data from MCRYPT.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command allows upgrading users to de-encrypt their deprecated mcrypt encrypted fields and re-encrypt them using the current OpenSSL encryption.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// Check and see if they have a legacy app key listed in their .env
// If not, we can try to use the current APP_KEY if looks like it's old
$legacy_key = env('LEGACY_APP_KEY');
$key_parts = explode(':', $legacy_key);
$legacy_cipher = env('LEGACY_CIPHER', 'rijndael-256');
$errors = [];
if (! $legacy_key) {
$this->error('ERROR: You do not have a LEGACY_APP_KEY set in your .env file. Please locate your old APP_KEY and ADD a line to your .env file like: LEGACY_APP_KEY=YOUR_OLD_APP_KEY');
return false;
}
// Do some basic legacy app key length checks
if (strlen($legacy_key) == 32) {
$legacy_length_check = true;
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1]) == 44)) {
$legacy_key = base64_decode($key_parts[1], true);
$legacy_length_check = true;
} else {
$legacy_length_check = false;
}
// Check that the app key is 32 characters
if ($legacy_length_check === true) {
$this->comment('INFO: Your LEGACY_APP_KEY looks correct. Okay to continue.');
} else {
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters or base64 followed by 44 characters for later versions). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
return false;
}
$this->error('================================!!!! WARNING !!!!================================');
$this->error('================================!!!! WARNING !!!!================================');
$this->comment("This tool will attempt to decrypt your old Snipe-IT (mcrypt, now deprecated) encrypted data and re-encrypt it using OpenSSL. \n\nYou should only continue if you have backed up any and all old APP_KEYs and have backed up your data.");
$force = ($this->option('force')) ? true : false;
if ($force || ($this->confirm('Are you SURE you wish to continue?'))) {
$backup_file = 'backups/env-backups/'.'app_key-'.date('Y-m-d-gis');
try {
Storage::disk('local')->put($backup_file, 'APP_KEY: '.config('app.key'));
Storage::disk('local')->append($backup_file, 'LEGACY_APP_KEY: '.$legacy_key);
} catch (\Exception $e) {
$this->info('WARNING: Could not backup app keys');
}
if ($legacy_cipher) {
$mcrypter = new McryptEncrypter($legacy_key, $legacy_cipher);
} else {
$mcrypter = new McryptEncrypter($legacy_key);
}
$settings = Setting::getSettings();
if ($settings->ldap_pword == '') {
$this->comment('INFO: No LDAP password found. Skipping... ');
} else {
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
$settings->ldap_pword = Crypt::encrypt($decrypted_ldap_pword);
$settings->save();
}
/** @var CustomField[] $custom_fields */
$custom_fields = CustomField::where('field_encrypted', '=', 1)->get();
$this->comment('INFO: Retrieving encrypted custom fields...');
$query = Asset::withTrashed();
foreach ($custom_fields as $custom_field) {
$this->comment('FIELD TO RECRYPT: '.$custom_field->name.' ('.$custom_field->db_column.')');
$query->orWhereNotNull($custom_field->db_column);
}
// Get all assets with a value in any of the fields that were encrypted
/** @var Asset[] $assets */
$assets = $query->get();
$bar = $this->output->createProgressBar(count($assets));
foreach ($assets as $asset) {
foreach ($custom_fields as $encrypted_field) {
$columnName = $encrypted_field->db_column;
// Make sure the value isn't null
if ($asset->{$columnName} != '') {
// Try to decrypt the payload using the legacy app key
try {
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
$asset->{$columnName} = Crypt::encrypt($decrypted_field);
$this->comment($decrypted_field);
} catch (\Exception $e) {
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
}
}
}
$asset->save();
$bar->advance();
}
$bar->finish();
if (count($errors) > 0) {
$this->comment("\n\n");
$this->error("The decrypter encountered some errors: \n");
foreach ($errors as $error) {
$this->error($error);
}
}
}
}
}

View File

@@ -289,6 +289,7 @@ class RestoreFromBackup extends Command
$interesting_files = [];
$boring_files = [];
$unsafe_files = [];
for ($i = 0; $i < $za->numFiles; $i++) {
$stat_results = $za->statIndex($i);
@@ -328,7 +329,8 @@ 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',];
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico', 'avif'
];
foreach (array_merge($private_files, $public_files) as $file) {
$has_wildcard = (strpos($file, '*') !== false);
if ($has_wildcard) {
@@ -338,7 +340,9 @@ class RestoreFromBackup extends Command
if ($last_pos !== false) {
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
if (!in_array($extension, $good_extensions)) {
$this->warn('Potentially unsafe file ' . $raw_path . ' is being skipped');
// gathering potentially unsafe files here to return at exit
$unsafe_files[] = $raw_path;
Log::debug('Potentially unsafe file '.$raw_path.' is being skipped');
$boring_files[] = $raw_path;
continue 2;
}
@@ -372,6 +376,7 @@ class RestoreFromBackup extends Command
if ($this->option('sanitize-guess-prefix')) {
$prefix = SQLStreamer::guess_prefix($sql_contents);
$this->line($prefix);
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitize your SQL.");
}
@@ -505,6 +510,11 @@ class RestoreFromBackup extends Command
} else {
$this->info(count($interesting_files).' files were succesfully transferred');
}
if (count($unsafe_files) > 0) {
foreach ($unsafe_files as $unsafe_file) {
$this->warn('Potentially unsafe file '.$unsafe_file.' was skipped');
}
}
foreach ($boring_files as $boring_file) {
$this->warn($boring_file.' was skipped.');
}

View File

@@ -64,28 +64,43 @@ class SendAcceptanceReminder extends Command
->groupBy(function($item) {
return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : '';
});
$no_email_list= [];
foreach($unacceptedAssetGroups as $unacceptedAssetGroup) {
// The [0] is weird, but it allows for the item_count to work and grabs the appropriate info for each user.
// Collapsing and flattening the collection doesn't work above.
$acceptance = $unacceptedAssetGroup[0]['acceptance'];
$locale = $acceptance->assignedTo?->locale;
$email = $acceptance->assignedTo?->email;
if(!$email){
$this->info($acceptance->assignedTo?->present()->fullName().' has no email address.');
$no_email_list[] = [
'id' => $acceptance->assignedTo?->id,
'name' => $acceptance->assignedTo?->present()->fullName(),
];
} else {
$count++;
}
$item_count = $unacceptedAssetGroup->count();
if ($locale && $email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count))->locale($locale));
} elseif ($email) {
Mail::to($email)->send((new UnacceptedAssetReminderMail($acceptance, $item_count)));
}
$count++;
}
$this->info($count.' users notified.');
$headers = ['ID', 'Name'];
$rows = [];
foreach ($no_email_list as $user) {
$rows[] = [$user['id'], $user['name']];
}
$this->info("The following users do not have an email address:");
$this->table($headers, $rows);
return 0;
}

View File

@@ -42,27 +42,28 @@ class SendExpirationAlerts extends Command
public function handle()
{
$settings = Setting::getSettings();
$threshold = $settings->alert_interval;
$alert_interval = $settings->alert_interval;
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {
// Send a rollup to the admin, if settings dictate
$recipients = collect(explode(',', $settings->alert_email))
->map(fn($item) => trim($item)) // Trim each email
->filter(fn($item) => !empty($item))
->all();
// Expiring Assets
$assets = Asset::getExpiringWarrantee($threshold);
$assets = Asset::getExpiringWarrantee($alert_interval);
if ($assets->count() > 0) {
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $threshold));
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval]));
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
}
// Expiring licenses
$licenses = License::getExpiringLicenses($threshold);
$licenses = License::getExpiringLicenses($alert_interval);
if ($licenses->count() > 0) {
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold]));
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $threshold));
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval]));
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval));
}
} else {
if ($settings->alert_email == '') {

View File

@@ -2,13 +2,12 @@
namespace App\Console\Commands;
use App\Mail\SendUpcomingAuditMail;
use App\Models\Asset;
use App\Models\Recipients\AlertRecipient;
use App\Models\Setting;
use App\Notifications\SendUpcomingAuditNotification;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendUpcomingAuditReport extends Command
{
@@ -48,19 +47,20 @@ class SendUpcomingAuditReport extends Command
$today = Carbon::now();
$interval_date = $today->copy()->addDays($interval);
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
$this->info($assets->count().' assets must be audited in on or before '.$interval_date.' is deadline');
$assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
$this->info($assets->count() . ' assets must be audited in on or before ' . $interval_date . ' is deadline');
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
if ((count($assets) !== 0) && ($assets->count() > 0) && ($settings->alert_email != '')) {
// Send a rollup to the admin, if settings dictate
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
return new AlertRecipient($item);
});
$recipients = collect(explode(',', $settings->alert_email))
->map(fn($item) => trim($item))
->filter(fn($item) => !empty($item))
->all();
$this->info('Sending Admin SendUpcomingAuditNotification to: '.$settings->alert_email);
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
$this->info('Sending Admin SendUpcomingAuditNotification to: ' . $settings->alert_email);
Mail::to($recipients)->send(new SendUpcomingAuditMail($assets, $settings->audit_warning_days));
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use App\Helpers\Helper;
use Illuminate\Console\Command;
class TestLocationsFMCS extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:test-locations-fmcs {--location_id=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Test for company ID inconsistencies if FullMultipleCompanySupport with scoped locations will be used.';
/**
* Execute the console command.
*/
public function handle()
{
$this->info('This script checks for company ID inconsistencies if Full Multiple Company Support with scoped locations will be used.');
$this->info('This could take a few moments if have a very large dataset.');
$this->newLine();
// if parameter location_id is set, only test this location
$location_id = null;
if ($this->option('location_id')) {
$location_id = $this->option('location_id');
}
$mismatched = Helper::test_locations_fmcs(true, $location_id);
$this->warn(trans_choice('admin/settings/message.location_scoping.mismatch', count($mismatched)));
$this->newLine();
$this->info('Edit your locations to associate them with the correct company.');
$header = ['Type', 'ID', 'Name', 'Checkout Type', 'Company ID', 'Item Company', 'Item Location', 'Location Company', 'Location Company ID'];
sort($mismatched);
$this->table($header, $mismatched);
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Console;
use App\Console\Commands\ImportLocations;
use App\Console\Commands\ReEncodeCustomFieldNames;
use App\Console\Commands\RestoreDeletedUsers;
use App\Models\Setting;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -18,12 +19,14 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
if(Setting::getSettings()?->alerts_enabled === 1) {
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
}
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
$schedule->command('auth:clear-resets')->everyFifteenMinutes();
$schedule->command('saml:clear_expired_nonces')->weekly();
}

View File

@@ -0,0 +1,9 @@
<?php
namespace App\Exceptions;
use Exception;
class AssetNotRequestable extends Exception
{
}

View File

@@ -125,7 +125,9 @@ class Handler extends ExceptionHandler
// This is traaaaash but it handles models that are not found while using route model binding :(
// The only alternative is to set that at *each* route, which is crazypants
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
$model_name = last(explode('\\', $e->getModel()));
// This gets the MVC model name from the exception and formats in a way that's less fugly
$model_name = strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel())))));
$route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index';
// Sigh.
@@ -137,6 +139,10 @@ class Handler extends ExceptionHandler
$route = 'models.index';
} elseif ($route == 'predefinedkits.index') {
$route = 'kits.index';
} elseif ($route == 'assetmaintenances.index') {
$route = 'maintenances.index';
} elseif ($route === 'licenseseats.index') {
$route = 'licenses.index';
}
return redirect()
@@ -199,4 +205,4 @@ class Handler extends ExceptionHandler
//
});
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Exceptions;
use Exception;
class UserDoestExistException extends Exception
{
}

View File

@@ -12,6 +12,7 @@ use App\Models\Depreciation;
use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\License;
use App\Models\Location;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Contracts\Encryption\DecryptException;
use Carbon\Carbon;
@@ -868,7 +869,7 @@ class Helper
$filetype = @finfo_file($finfo, $file);
finfo_close($finfo);
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif') || ($filetype == 'image/avif')) {
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif') || ($filetype == 'image/avif') || ($filetype == 'image/webp')) {
return $filetype;
}
@@ -895,6 +896,12 @@ class Helper
public static function selectedPermissionsArray($permissions, $selected_arr = [])
{
$permissions_arr = [];
if (is_array($permissions)) {
$permissions = json_encode($permissions);
}
// Set default to empty JSON if the value is null
$permissions = json_decode($permissions ?? '{}', JSON_OBJECT_AS_ARRAY);
foreach ($permissions as $permission) {
for ($x = 0; $x < count($permission); $x++) {
@@ -905,13 +912,13 @@ class Helper
if (is_array($selected_arr)) {
if (array_key_exists($permission_name, $selected_arr)) {
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
$permissions_arr[$permission_name] = (int) $selected_arr[$permission_name];
} else {
$permissions_arr[$permission_name] = '0';
$permissions_arr[$permission_name] = 0;
}
} else {
$permissions_arr[$permission_name] = '0';
$permissions_arr[$permission_name] = 0;
}
}
}
@@ -1479,6 +1486,8 @@ class Helper
$redirect_option = Session::get('redirect_option');
$checkout_to_type = Session::get('checkout_to_type');
$checkedInFrom = Session::get('checkedInFrom');
$other_redirect = Session::get('other_redirect');
// return to index
if ($redirect_option == 'index') {
@@ -1520,13 +1529,129 @@ class Helper
if ($redirect_option == 'target') {
switch ($checkout_to_type) {
case 'user':
return route('users.show', $request->assigned_user);
return route('users.show', $request->assigned_user ?? $checkedInFrom);
case 'location':
return route('locations.show', $request->assigned_location);
return route('locations.show', $request->assigned_location ?? $checkedInFrom);
case 'asset':
return route('hardware.show', $request->assigned_asset);
return route('hardware.show', $request->assigned_asset ?? $checkedInFrom);
}
}
// return to somewhere else
if ($redirect_option == 'other_redirect') {
switch ($other_redirect) {
case 'audit':
return route('assets.audit.due');
}
}
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));
}
/**
* Check for inconsistencies before activating scoped locations with FullMultipleCompanySupport
* If there are locations with different companies than related objects unforseen problems could arise
*
* @author T. Regnery <tobias.regnery@gmail.com>
* @since 7.0
*
* @param $artisan when false, bail out on first inconsistent entry
* @param $location_id when set, only test this specific location
* @param $new_company_id in case of updating a location, this is the newly requested company_id
* @return string []
*/
static public function test_locations_fmcs($artisan, $location_id = null, $new_company_id = null) {
$mismatched = [];
if ($location_id) {
$location = Location::find($location_id);
if ($location) {
$locations = collect([])->push(Location::find($location_id));
}
} else {
$locations = Location::all();
}
// Bail out early if there are no locations
if ($locations->count() == 0) {
return [];
}
foreach($locations as $location) {
// in case of an update of a single location, use the newly requested company_id
if ($new_company_id) {
$location_company = $new_company_id;
} else {
$location_company = $location->company_id;
}
// Depending on the relationship, we must use different operations to retrieve the objects
$keywords_relation = [
'many' => [
'accessories',
'assets',
'assignedAccessories',
'assignedAssets',
'components',
'consumables',
'rtd_assets',
'users',
],
'one' => [
'manager',
'parent',
]];
// In case of a single location, the children must be checked as well, because we don't walk every location
if ($location_id) {
$keywords_relation['many'][] = 'children';
}
foreach ($keywords_relation as $relation => $keywords) {
foreach($keywords as $keyword) {
if ($relation == 'many') {
$items = $location->{$keyword}->all();
} else {
$items = collect([])->push($location->$keyword);
}
$count = 0;
foreach ($items as $item) {
if ($item && $item->company_id != $location_company) {
$mismatched[] = [
class_basename(get_class($item)),
$item->id,
$item->name ?? $item->asset_tag ?? $item->serial ?? $item->username,
$item->assigned_type ? str_replace('App\\Models\\', '', $item->assigned_type) : null,
$item->company_id ?? null,
$item->company->name ?? null,
// $item->defaultLoc->id ?? null,
// $item->defaultLoc->name ?? null,
// $item->defaultLoc->company->id ?? null,
// $item->defaultLoc->company->name ?? null,
$item->location->name ?? null,
$item->location->company->name ?? null,
$location_company ?? null,
];
$count++;
// Bail early if this is not being run via artisan
if ((!$artisan) && ($count > 0)) {
return $mismatched;
}
}
}
}
}
}
return $mismatched;
}
}

View File

@@ -112,13 +112,13 @@ class AccessoriesController extends Controller
{
$this->authorize('create', Accessory::class);
$accessory = clone $accessory;
$accessory->id = null;
$accessory->location_id = null;
$cloned = clone $accessory;
$cloned->id = null;
$cloned->deleted_at = '';
$cloned->location_id = null;
return view('accessories/edit')
->with('item', $accessory);
->with('item', $cloned);
}
@@ -184,15 +184,15 @@ class AccessoriesController extends Controller
*/
public function destroy($accessoryId) : RedirectResponse
{
if (is_null($accessory = Accessory::find($accessoryId))) {
if (is_null($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
}
$this->authorize($accessory);
if ($accessory->hasUsers() > 0) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', ['count'=> $accessory->hasUsers()]));
if ($accessory->checkouts_count > 0) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/general.delete_disabled'));
}
if ($accessory->image) {

View File

@@ -7,7 +7,6 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use \Illuminate\Contracts\View\View;
@@ -30,9 +29,17 @@ class AccessoryCheckinController extends Controller
}
$accessory = Accessory::find($accessory_user->accessory_id);
//based on what the accessory is checked out to the target redirect option will be displayed accordingly.
$target_option = match ($accessory_user->assigned_type) {
'App\Models\Asset' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.asset')]),
'App\Models\Location' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.location')]),
default => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.user')]),
};
$this->authorize('checkin', $accessory);
return view('accessories/checkin', compact('accessory'))->with('backto', $backto);
return view('accessories/checkin', compact('accessory', 'target_option'))->with('backto', $backto);
}
/**
@@ -51,8 +58,14 @@ class AccessoryCheckinController extends Controller
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
session()->put('checkedInFrom', $accessory_checkout->assigned_to);
session()->put('checkout_to_type', match ($accessory_checkout->assigned_type) {
'App\Models\User' => 'user',
'App\Models\Location' => 'location',
'App\Models\Asset' => 'asset',
});
$this->authorize('checkin', $accessory);
$checkin_hours = date('H:i:s');
$checkin_at = date('Y-m-d H:i:s');
if ($request->filled('checkin_at')) {

View File

@@ -208,9 +208,12 @@ class AcceptanceController extends Controller
*/
$branding_settings = SettingsController::getPDFBranding();
if (is_null($branding_settings->logo)){
$path_logo = "";
} else {
$path_logo = "";
// Check for the PDF logo path and use that, otherwise use the regular logo path
if (!is_null($branding_settings->acceptance_pdf_logo)) {
$path_logo = public_path() . '/uploads/' . $branding_settings->acceptance_pdf_logo;
} elseif (!is_null($branding_settings->logo)) {
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
}

View File

@@ -66,7 +66,7 @@ class AccessoriesController extends Controller
}
if ($request->filled('company_id')) {
$accessories->where('company_id', '=', $request->input('company_id'));
$accessories->where('accessories.company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {
@@ -249,11 +249,11 @@ class AccessoriesController extends Controller
public function destroy($id)
{
$this->authorize('delete', Accessory::class);
$accessory = Accessory::findOrFail($id);
$accessory = Accessory::withCount('checkouts as checkouts_count')->findOrFail($id);
$this->authorize($accessory);
if ($accessory->hasUsers() > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.assoc_users', ['count'=> $accessory->hasUsers()])));
if ($accessory->checkouts_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/general.delete_disabled')));
}
$accessory->delete();

View File

@@ -3,6 +3,7 @@
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;
@@ -13,6 +14,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Illuminate\Http\Request;
/**
@@ -72,33 +74,37 @@ class AssetFilesController extends Controller
* @since [v6.0]
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
*/
public function list($assetId = null) : JsonResponse
public function list(Asset $asset, Request $request) : JsonResponse | array
{
// Start by checking if the asset being acted upon exists
if (! $asset = Asset::find($assetId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
}
// the asset is valid
if (isset($asset->id)) {
$this->authorize('view', $asset);
// Check that there are some uploads on this asset that can be listed
if ($asset->uploads->count() > 0) {
$files = array();
foreach ($asset->uploads as $upload) {
array_push($files, $upload);
}
// Give the list of files back to the user
return response()->json(Helper::formatStandardApiResponse('success', $files, trans('admin/hardware/message.upload.success')));
}
$this->authorize('view', $asset);
// There are no files.
return response()->json(Helper::formatStandardApiResponse('success', array(), trans('admin/hardware/message.upload.success')));
$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'));
}
// Send back an error message
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error')), 500);
// 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());
}
/**
@@ -111,12 +117,8 @@ class AssetFilesController extends Controller
* @since [v6.0]
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
*/
public function show($assetId = null, $fileId = null) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
public function show(Asset $asset, $fileId = null) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
{
// Start by checking if the asset being acted upon exists
if (! $asset = Asset::find($assetId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
}
// the asset is valid
if (isset($asset->id)) {
@@ -164,12 +166,8 @@ class AssetFilesController extends Controller
* @since [v6.0]
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
*/
public function destroy($assetId = null, $fileId = null) : JsonResponse
public function destroy(Asset $asset, $fileId = 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);
}
$rel_path = 'private_uploads/assets';
@@ -179,12 +177,14 @@ class AssetFilesController extends Controller
// 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
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

View File

@@ -75,6 +75,11 @@ class AssetModelFilesController extends Controller
*/
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());

View File

@@ -77,6 +77,18 @@ class AssetModelsController extends Controller
$assetmodels->onlyTrashed();
}
if ($request->filled('name')) {
$assetmodels = $assetmodels->where('models.name', '=', $request->input('name'));
}
if ($request->filled('model_number')) {
$assetmodels = $assetmodels->where('models.model_number', '=', $request->input('model_number'));
}
if ($request->filled('notes')) {
$assetmodels = $assetmodels->where('models.notes', '=', $request->input('notes'));
}
if ($request->filled('category_id')) {
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
}

View File

@@ -34,6 +34,7 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use App\View\Label;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
/**
@@ -297,9 +298,15 @@ class AssetsController extends Controller
if ($request->input('requestable') == 'true') {
$assets->where('assets.requestable', '=', '1');
}
if ($request->filled('model_id')) {
$assets->InModelList([$request->input('model_id')]);
// If model_id is already an array, just use it as-is
if (is_array($request->input('model_id'))) {
$assets->InModelList($request->input('model_id'));
} else {
// Otherwise, turn it into an array
$assets->InModelList([$request->input('model_id')]);
}
}
if ($request->filled('category_id')) {
@@ -435,12 +442,6 @@ class AssetsController extends Controller
}]);
}
/**
* Here we're just determining which Transformer (via $transformer) to use based on the
* variables we set earlier on in this method - we default to AssetsTransformer.
*/
return (new $transformer)->transformAssets($assets, $total, $request);
}
@@ -491,15 +492,32 @@ class AssetsController extends Controller
public function showBySerial(Request $request, $serial): JsonResponse | array
{
$this->authorize('index', Asset::class);
$assets = Asset::where('serial', $serial)->with('assetstatus')->with('assignedTo');
$assets = Asset::where('serial', $serial)->with([
'assetstatus',
'assignedTo',
'company',
'defaultLoc',
'location',
'model.category',
'model.depreciation',
'model.fieldset',
'model.manufacturer',
'supplier',
]);
// Check if they've passed ?deleted=true
if ($request->input('deleted', 'false') == 'true') {
$assets = $assets->withTrashed();
}
if (($assets = $assets->get()) && ($assets->count()) > 0) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : app('api_offset_value');
$limit = app('api_limit_value');
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
if (($assets) && ($assets->count()) > 0) {
return (new AssetsTransformer)->transformAssets($assets, $total);
}
// If there are 0 results, return the "no such asset" response
@@ -556,7 +574,12 @@ class AssetsController extends Controller
'assets.assigned_to',
'assets.assigned_type',
'assets.status_id',
])->with('model', 'assetstatus', 'assignedTo')->NotArchived();
])->with('model', 'assetstatus', 'assignedTo')
->NotArchived();
if ((Setting::getSettings()->full_multiple_companies_support=='1') && ($request->filled('companyId'))) {
$assets->where('assets.company_id', $request->input('companyId'));
}
if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') {
$assets = $assets->RTD();
@@ -566,7 +589,6 @@ class AssetsController extends Controller
$assets = $assets->AssignedSearch($request->input('search'));
}
$assets = $assets->paginate(50);
// Loop through and set some custom properties for the transformer to use.
@@ -679,7 +701,9 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success')));
// below is what we want the _eventual_ return to look like - in a more standardized format.
// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
@@ -1047,7 +1071,7 @@ class AssetsController extends Controller
* @param int $id
* @since [v4.0]
*/
public function audit(Request $request): JsonResponse
public function audit(Request $request, Asset $asset): JsonResponse
{
$this->authorize('audit', Asset::class);
@@ -1055,36 +1079,15 @@ class AssetsController extends Controller
$settings = Setting::getSettings();
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
// No tag passed - return an error
if (!$request->filled('asset_tag')) {
return response()->json(Helper::formatStandardApiResponse('error', [
'asset_tag' => '',
'error' => trans('admin/hardware/message.no_tag'),
], trans('admin/hardware/message.no_tag')), 200);
// Allow the asset tag to be passed in the payload (legacy method)
if ($request->filled('asset_tag')) {
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
}
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
if ($asset) {
/**
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
* the audit log entry we're creating through this controller.
*
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
* will bypass normal model-level validation that's usually handled at the observer )
*
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
* which manually invokes Watson Validating to make sure the asset's model is valid.
*
* @see \App\Observers\AssetObserver::updating()
*/
$asset->unsetEventDispatcher();
$originalValues = $asset->getRawOriginal();
$asset->next_audit_date = $dt;
if ($request->filled('next_audit_date')) {
@@ -1099,33 +1102,89 @@ class AssetsController extends Controller
$asset->last_audit_date = date('Y-m-d H:i:s');
// Set up the payload for re-display in the API response
$payload = [
'id' => $asset->id,
'asset_tag' => $asset->asset_tag,
'note' => $request->input('note'),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
];
/**
* Update custom fields in the database.
* Validation for these fields is handled through the AssetRequest form request
* $model = AssetModel::find($request->get('model_id'));
*/
if (($asset->model) && ($asset->model->fieldset)) {
$payload['custom_fields'] = [];
foreach ($asset->model->fieldset->fields as $field) {
if (($field->display_audit=='1') && ($request->has($field->db_column))) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
}
}
$payload['custom_fields'][$field->db_column] = $request->input($field->db_column);
}
}
}
// Validate custom fields
Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate();
// Validate the rest of the data before we turn off the event dispatcher
if ($asset->isInvalid()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()));
}
/**
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
* the audit log entry we're creating through this controller.
*
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
* will bypass normal model-level validation that's usually handled at the observer)
*
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
* which manually invokes Watson Validating to make sure the asset's model is valid.
*
* @see \App\Observers\AssetObserver::updating()
* @see \App\Models\Asset::save()
*/
$asset->unsetEventDispatcher();
/**
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
* We have to invoke this manually because of the unsetEventDispatcher() above.)
*/
if ($asset->isValid() && $asset->save()) {
$asset->logAudit(request('note'), request('location_id'));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag' => e($asset->asset_tag),
'note' => e($request->input('note')),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
], trans('admin/hardware/message.audit.success')));
$asset->logAudit(request('note'), request('location_id'), null, $originalValues);
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/hardware/message.audit.success')));
}
// Asset failed validation or was not able to be saved
return response()->json(Helper::formatStandardApiResponse('error', [
'asset_tag' => e($asset->asset_tag),
'error' => $asset->getErrors()->first(),
], trans('admin/hardware/message.audit.error', ['error' => $asset->getErrors()->first()])), 200);
}
// No matching asset for the asset tag that was passed.
return response()->json(Helper::formatStandardApiResponse('error', [
'asset_tag' => e($request->input('asset_tag')),
'error' => trans('admin/hardware/message.audit.error'),
], trans('admin/hardware/message.audit.error', ['error' => trans('admin/hardware/message.does_not_exist')])), 200);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers\Api;
use App\Actions\CheckoutRequests\CancelCheckoutRequestAction;
use App\Actions\CheckoutRequests\CreateCheckoutRequestAction;
use App\Exceptions\AssetNotRequestable;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\JsonResponse;
use Exception;
class CheckoutRequest extends Controller
{
public function store(Asset $asset): JsonResponse
{
try {
CreateCheckoutRequestAction::run($asset, auth()->user());
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.requests.success')));
} catch (AssetNotRequestable $e) {
return response()->json(Helper::formatStandardApiResponse('error', 'Asset is not requestable'));
} catch (AuthorizationException $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.insufficient_permissions')));
} catch (Exception $e) {
report($e);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
}
}
public function destroy(Asset $asset): JsonResponse
{
try {
CancelCheckoutRequestAction::run($asset, auth()->user());
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.requests.canceled')));
} catch (AuthorizationException $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.insufficient_permissions')));
} catch (Exception $e) {
report($e);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
}
}
}

View File

@@ -60,7 +60,7 @@ class ComponentsController extends Controller
}
if ($request->filled('company_id')) {
$components->where('company_id', '=', $request->input('company_id'));
$components->where('components.company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {

View File

@@ -40,7 +40,7 @@ class ConsumablesController extends Controller
}
if ($request->filled('company_id')) {
$consumables->where('company_id', '=', $request->input('company_id'));
$consumables->where('consumables.company_id', '=', $request->input('company_id'));
}
if ($request->filled('category_id')) {

View File

@@ -76,7 +76,7 @@ class GroupsController extends Controller
$this->authorize('superadmin');
$group = new Group;
// Get all the available permissions
$permissions = config('permissions');
$permissions = json_encode(config('permissions'));
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
$group->name = $request->input('name');

View File

@@ -66,25 +66,41 @@ class ImportController extends Controller
if (! ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
$encoding = $detector->getEncoding($file_contents);
$reader = null;
if (strcasecmp($encoding, 'UTF-8') != 0) {
$transliterated = iconv($encoding, 'UTF-8', $file_contents);
if ($transliterated !== false) {
$tmpname = tempnam(sys_get_temp_dir(), '');
$tmpresults = file_put_contents($tmpname, $transliterated);
if ($tmpresults !== false) {
if (function_exists('iconv')) {
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
$encoding = $detector->getEncoding($file_contents);
\Log::warning("Discovered encoding: $encoding in uploaded CSV");
$reader = null;
if (strcasecmp($encoding, 'UTF-8') != 0) {
$transliterated = false;
try {
$transliterated = iconv(strtoupper($encoding), 'UTF-8', $file_contents);
} catch (\Exception $e) {
$transliterated = false; //blank out the partially-decoded string
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.transliterate_failure', ["encoding" => $encoding])
),
422
);
}
if ($transliterated !== false) {
$tmpname = tempnam(sys_get_temp_dir(), '');
$tmpresults = file_put_contents($tmpname, $transliterated);
$transliterated = null; //save on memory?
$newfile = new UploadedFile($tmpname, $file->getClientOriginalName(), null, null, true); //WARNING: this is enabling 'test mode' - which is gross, but otherwise the file won't be treated as 'uploaded'
if ($newfile->isValid()) {
$file = $newfile;
if ($tmpresults !== false) {
$newfile = new UploadedFile($tmpname, $file->getClientOriginalName(), null, null, true); //WARNING: this is enabling 'test mode' - which is gross, but otherwise the file won't be treated as 'uploaded'
if ($newfile->isValid()) {
$file = $newfile;
}
}
}
}
$file_contents = null; //try to save on memory, I guess?
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$file_contents = null; //try to save on memory, I guess?
try {
$import->header_row = $reader->fetchOne(0);

View File

@@ -136,13 +136,13 @@ class LicenseSeatsController extends Controller
if ($licenseSeat->save()) {
if ($is_checkin) {
$licenseSeat->logCheckin($target, $request->input('note'));
$licenseSeat->logCheckin($target, $request->input('notes'));
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
// in this case, relevant fields are touched but it's not a checkin operation. so it must be a checkout operation.
$licenseSeat->logCheckout($request->input('note'), $target);
$licenseSeat->logCheckout($request->input('notes'), $target);
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}

View File

@@ -12,7 +12,9 @@ use App\Http\Transformers\SelectlistTransformer;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Location;
use App\Models\Setting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -46,6 +48,7 @@ class LocationsController extends Controller
'id',
'image',
'ldap_ou',
'company_id',
'manager_id',
'name',
'rtd_assets_count',
@@ -74,8 +77,10 @@ class LocationsController extends Controller
'locations.image',
'locations.ldap_ou',
'locations.currency',
'locations.company_id',
'locations.notes',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
@@ -84,6 +89,11 @@ class LocationsController extends Controller
->withCount('children as children_count')
->withCount('users as users_count');
// Only scope locations if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$locations = Company::scopeCompanyables($locations);
}
if ($request->filled('search')) {
$locations = $locations->TextSearch($request->input('search'));
}
@@ -116,6 +126,10 @@ class LocationsController extends Controller
$locations->where('locations.manager_id', '=', $request->input('manager_id'));
}
if ($request->filled('company_id')) {
$locations->where('locations.company_id', '=', $request->input('company_id'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -132,6 +146,9 @@ class LocationsController extends Controller
case 'manager':
$locations->OrderManager($order);
break;
case 'company':
$locations->OrderCompany($order);
break;
default:
$locations->orderBy($sort, $order);
break;
@@ -159,6 +176,15 @@ class LocationsController extends Controller
$location->fill($request->all());
$location = $request->handleImages($location);
// Only scope location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->get('company_id'));
// check if parent is set and has a different company
if ($location->parent_id && Location::find($location->parent_id)->company_id != $location->company_id) {
response()->json(Helper::formatStandardApiResponse('error', null, 'different company than parent'));
}
}
if ($location->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new LocationsTransformer)->transformLocation($location), trans('admin/locations/message.create.success')));
}
@@ -176,7 +202,7 @@ class LocationsController extends Controller
public function show($id) : JsonResponse | array
{
$this->authorize('view', Location::class);
$location = Location::with('parent', 'manager', 'children')
$location = Location::with('parent', 'manager', 'children', 'company')
->select([
'locations.id',
'locations.name',
@@ -220,6 +246,19 @@ class LocationsController extends Controller
$location->fill($request->all());
$location = $request->handleImages($location);
if ($request->filled('company_id')) {
// Only scope location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->get('company_id'));
// check if there are related objects with different company
if (Helper::test_locations_fmcs(false, $id, $location->company_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'error scoped locations'));
}
} else {
$location->company_id = $request->get('company_id');
}
}
if ($location->isValid()) {
$location->save();
@@ -340,6 +379,11 @@ class LocationsController extends Controller
'locations.image',
]);
// Only scope locations if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$locations = Company::scopeCompanyables($locations);
}
$page = 1;
if ($request->filled('page')) {
$page = $request->input('page');

View File

@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Transformers\ActionlogsTransformer;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
@@ -18,10 +20,11 @@ class ReportsController extends Controller
*/
public function index(Request $request) : JsonResponse | array
{
$this->authorize('reports.view');
$this->authorize('activity.view');
$actionlogs = Actionlog::with('item', 'user', 'adminuser', 'target', 'location');
if ($request->filled('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
}

View File

@@ -290,10 +290,12 @@ class StatuslabelsController extends Controller
/**
* Returns a boolean response based on whether the status label
* is one that is deployable.
* is one that is deployable or pending.
*
* This is used by the hardware create/edit view to determine whether
* we should provide a dropdown of users for them to check the asset out to.
* we should provide a dropdown of users for them to check the asset out to,
* and whether we show a warning that the asset will be checked in if it's already
* assigned but the status is changed to one that isn't pending or deployable
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
@@ -301,7 +303,7 @@ class StatuslabelsController extends Controller
public function checkIfDeployable($id) : string
{
$statuslabel = Statuslabel::findOrFail($id);
if ($statuslabel->getStatuslabelType() == 'deployable') {
if (($statuslabel->getStatuslabelType() == 'pending') || ($statuslabel->getStatuslabelType() == 'deployable')) {
return '1';
}

View File

@@ -339,6 +339,7 @@ class UsersController extends Controller
$users = $users->where(function ($query) use ($request) {
$query->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('email', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
});
}

View File

@@ -117,7 +117,7 @@ class AssetMaintenancesController extends Controller
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
$assetMaintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
}
// Was the asset maintenance created?
@@ -210,7 +210,7 @@ class AssetMaintenancesController extends Controller
) {
$startDate = Carbon::parse($maintenance->start_date);
$completionDate = Carbon::parse($maintenance->completion_date);
$maintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
$maintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
}
// Was the asset maintenance created?

View File

@@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
use \Illuminate\Contracts\View\View;
use \Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Validator;
class AssetCheckinController extends Controller
{
@@ -41,7 +42,20 @@ class AssetCheckinController extends Controller
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
return view('hardware/checkin', compact('asset'))
// Validate custom fields on existing asset
$validator = Validator::make($asset->toArray(), $asset->customFieldValidationRules());
if ($validator->fails()) {
return redirect()->route('hardware.edit', $asset)
->withErrors($validator);
}
$target_option = match ($asset->assigned_type) {
'App\Models\Asset' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.asset_previous')]),
'App\Models\Location' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.location')]),
default => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.user')]),
};
return view('hardware/checkin', compact('asset', 'target_option'))
->with('item', $asset)
->with('statusLabel_list', Helper::statusLabelList())
->with('backto', $backto)
@@ -75,9 +89,12 @@ class AssetCheckinController extends Controller
$this->authorize('checkin', $asset);
if ($asset->assignedType() == Asset::USER) {
$user = $asset->assignedTo;
}
session()->put('checkedInFrom', $asset->assignedTo->id);
session()->put('checkout_to_type', match ($asset->assigned_type) {
'App\Models\User' => 'user',
'App\Models\Location' => 'location',
'App\Models\Asset' => 'asset',
});
$asset->expected_checkin = null;
$asset->last_checkin = now();

View File

@@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Session;
use \Illuminate\Contracts\View\View;
use \Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Validator;
class AssetCheckoutController extends Controller
{
@@ -36,6 +37,14 @@ class AssetCheckoutController extends Controller
->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
// Validate custom fields on existing asset
$validator = Validator::make($asset->toArray(), $asset->customFieldValidationRules());
if ($validator->fails()) {
return redirect()->route('hardware.edit', $asset)
->withErrors($validator);
}
if ($asset->availableForCheckout()) {
return view('hardware/checkout', compact('asset'))
->with('statusLabel_list', Helper::deployableStatusLabelList())

View File

@@ -71,12 +71,12 @@ class AssetFilesController extends Controller
try {
return StorageHelper::showOrDownloadFile($file, $log->filename);
} catch (\Exception $e) {
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.file_not_found'));
return redirect()->route('hardware.show', $asset)->with('error', trans('general.file_not_found'));
}
}
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
}
@@ -102,7 +102,7 @@ class AssetFilesController extends Controller
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
}
}

View File

@@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\UpdateAssetRequest;
use App\Models\Actionlog;
use App\Http\Requests\UploadFileRequest;
use Illuminate\Support\Facades\Log;
@@ -318,7 +319,7 @@ class AssetsController extends Controller
$asset->eol_explicit = false;
} elseif ($request->filled('asset_eol_date')) {
$asset->asset_eol_date = $request->input('asset_eol_date', null);
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
$months = (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true);
if($asset->model->eol) {
if($months != $asset->model->eol > 0) {
$asset->eol_explicit = true;
@@ -340,22 +341,16 @@ class AssetsController extends Controller
$status = Statuslabel::find($request->input('status_id'));
// This is a non-deployable status label - we should check the asset back in.
if (($status && $status->getStatuslabelType() != 'deployable') && ($target = $asset->assignedTo)) {
// This is an archived or undeployable - we should check the asset back in.
// Pending is allowed here
if (($status) && (($status->getStatuslabelType() != 'pending') && ($status->getStatuslabelType() != 'deployable')) && ($target = $asset->assignedTo)) {
$originalValues = $asset->getRawOriginal();
$asset->assigned_to = null;
$asset->assigned_type = null;
$asset->accepted = null;
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update', date('Y-m-d H:i:s'), $originalValues));
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues));
}
if ($asset->assigned_to == '') {
$asset->location_id = $request->input('rtd_location_id', null);
}
if ($request->filled('image_delete')) {
try {
unlink(public_path().'/uploads/assets/'.$asset->image);
@@ -391,26 +386,26 @@ class AssetsController extends Controller
$asset = $request->handleImages($asset);
// Update custom fields in the database.
// Validation for these fields is handlded through the AssetRequest form request
// FIXME: No idea why this is returning a Builder error on db_column_name.
// Need to investigate and fix. Using static method for now.
$model = AssetModel::find($request->get('model_id'));
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
if ($request->has($field->db_column)) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
}
}
}
}
@@ -524,7 +519,7 @@ class AssetsController extends Controller
{
$settings = Setting::getSettings();
if (($settings->qr_code == '1') && ($settings->label2_2d_type !== 'none')) {
if ($settings->label2_2d_type !== 'none') {
if ($asset) {
$size = Helper::barcodeDimensions($settings->label2_2d_type);
@@ -866,13 +861,6 @@ class AssetsController extends Controller
return view('hardware/quickscan-checkin')->with('statusLabel_list', Helper::statusLabelList());
}
public function audit(Asset $asset)
{
$settings = Setting::getSettings();
$this->authorize('audit', Asset::class);
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
public function dueForAudit()
{
@@ -889,19 +877,72 @@ class AssetsController extends Controller
}
public function auditStore(UploadFileRequest $request, Asset $asset)
public function audit(Asset $asset): View | RedirectResponse
{
$this->authorize('audit', Asset::class);
$settings = Setting::getSettings();
$rules = [
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable',
];
$validator = Validator::make($request->all(), $rules);
// Validate custom fields on existing asset
$validator = Validator::make($asset->toArray(), $asset->customFieldValidationRules());
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
return redirect()->route('hardware.edit', $asset)
->withErrors($validator);
}
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
return view('hardware/audit')->with('asset', $asset)->with('item', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
public function auditStore(UploadFileRequest $request, Asset $asset)
{
$this->authorize('audit', Asset::class);
session()->put('redirect_option', $request->get('redirect_option'));
session()->put('other_redirect', 'audit');
$originalValues = $asset->getRawOriginal();
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d H:i:s');
// Check to see if they checked the box to update the physical location,
// not just note it in the audit notes
if ($request->input('update_location') == '1') {
$asset->location_id = $request->input('location_id');
}
// Update custom fields in the database
if (($asset->model) && ($asset->model->fieldset)) {
foreach ($asset->model->fieldset->fields as $field) {
if (($field->display_audit=='1') && ($request->has($field->db_column))) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
}
}
}
}
}
// Validate custom fields
Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate();
// Validate the rest of the data before we turn off the event dispatcher
if ($asset->isInvalid()) {
return redirect()->back()->withInput()->withErrors($asset->getErrors());
}
/**
@@ -918,18 +959,11 @@ class AssetsController extends Controller
* which manually invokes Watson Validating to make sure the asset's model is valid.
*
* @see \App\Observers\AssetObserver::updating()
* @see \App\Models\Asset::save()
*/
$asset->unsetEventDispatcher();
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d H:i:s');
// Check to see if they checked the box to update the physical location,
// not just note it in the audit notes
if ($request->input('update_location') == '1') {
$asset->location_id = $request->input('location_id');
}
/**
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
@@ -943,8 +977,8 @@ class AssetsController extends Controller
$file_name = $request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image'));
}
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
$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 redirect()->back()->withInput()->withErrors($asset->getErrors());

View File

@@ -358,7 +358,11 @@ class BulkAssetsController extends Controller
* to someone/something.
*/
if ($request->filled('status_id')) {
$updated_status = Statuslabel::find($request->input('status_id'));
try {
$updated_status = Statuslabel::findOrFail($request->input('status_id'));
} catch (ModelNotFoundException $e) {
return redirect($bulk_back_url)->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
// We cannot assign a non-deployable status type if the asset is already assigned.
// This could probably be added to a form request.
@@ -366,7 +370,7 @@ class BulkAssetsController extends Controller
// Otherwise we need to make sure the status type is still a deployable one.
if (
($asset->assigned_to == '')
|| ($updated_status->deployable == '1') && ($asset->assetstatus->deployable == '1')
|| ($updated_status->deployable == '1') && ($asset->assetstatus?->deployable == '1')
) {
$this->update_array['status_id'] = $updated_status->id;
}
@@ -566,7 +570,6 @@ class BulkAssetsController extends Controller
*/
public function storeCheckout(AssetCheckoutRequest $request) : RedirectResponse | ModelNotFoundException
{
$this->authorize('checkout', Asset::class);
try {
@@ -580,6 +583,8 @@ class BulkAssetsController extends Controller
$asset_ids = array_filter($request->get('selected_assets'));
$assets = Asset::findOrFail($asset_ids);
if (request('checkout_to_type') == 'asset') {
foreach ($asset_ids as $asset_id) {
if ($target->id == $asset_id) {
@@ -599,9 +604,8 @@ class BulkAssetsController extends Controller
}
$errors = [];
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, &$errors, $asset_ids, $request) { //NOTE: $errors is passsed by reference!
foreach ($asset_ids as $asset_id) {
$asset = Asset::findOrFail($asset_id);
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, &$errors, $assets, $request) { //NOTE: $errors is passsed by reference!
foreach ($assets as $asset) {
$this->authorize('checkout', $asset);
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
@@ -628,7 +632,7 @@ class BulkAssetsController extends Controller
// Redirect to the asset management page with error
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans_choice('admin/hardware/message.multi-checkout.error', $asset_ids))->withErrors($errors);
} catch (ModelNotFoundException $e) {
return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors());
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans_choice('admin/hardware/message.multi-checkout.error', $request->input('selected_assets')));
}
}

View File

@@ -206,6 +206,7 @@ class LoginController extends Controller
$user->password = bcrypt($request->input('password'));
}
$user->last_login = \Carbon::now();
$user->email = $ldap_attr['email'];
$user->first_name = $ldap_attr['firstname'];
$user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc.
@@ -226,7 +227,7 @@ class LoginController extends Controller
$strip_prefixes = [
// IIS/AD
// https://github.com/snipe/snipe-it/pull/5862
// https://github.com/grokability/snipe-it/pull/5862
'\\',
// Google Cloud IAP
@@ -283,8 +284,11 @@ class LoginController extends Controller
return redirect()->back()->withInput()->withErrors($validator);
}
$this->maxLoginAttempts = config('auth.passwords.users.throttle.max_attempts');
$this->lockoutTime = config('auth.passwords.users.throttle.lockout_duration');
// Set the custom lockout attempts from the env and sett the custom lockout throttle from the env.
// We divide decayMinutes by 60 here to get minutes, since Laravel changed the default from minutes
// to seconds, and we don't want to break limits on existing systems
$this->maxAttempts = config('auth.passwords.users.throttle.max_attempts');
$this->decayMinutes = (config('auth.passwords.users.throttle.lockout_duration') / 60);
if ($lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
@@ -354,7 +358,7 @@ class LoginController extends Controller
// We wouldn't normally see this page if 2FA isn't enforced via the
// \App\Http\Middleware\CheckForTwoFactor middleware AND if a device isn't enrolled,
// but let's check check anyway in case there's a browser history or back button thing.
// but let's check anyway in case there's a browser history or back button thing.
// While you can access this page directly, enrolling a device when 2FA isn't enforced
// won't cause any harm.
@@ -432,6 +436,7 @@ class LoginController extends Controller
if (Google2FA::verifyKey($user->two_factor_secret, $secret)) {
$user->two_factor_enrolled = 1;
$user->last_login = \Carbon::now();
$user->saveQuietly();
$request->session()->put('2fa_authed', $user->id);
@@ -519,45 +524,6 @@ class LoginController extends Controller
return 'username';
}
/**
* Redirect the user after determining they are locked out.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendLockoutResponse(Request $request)
{
$seconds = $this->limiter()->availableIn(
$this->throttleKey($request)
);
$minutes = round($seconds / 60);
$message = trans('auth/message.throttle', ['minutes' => $minutes]);
return redirect()->back()
->withInput($request->only($this->username(), 'remember'))
->withErrors([$this->username() => $message]);
}
/**
* Override the lockout time and duration
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function hasTooManyLoginAttempts(Request $request)
{
$lockoutTime = config('auth.passwords.users.throttle.lockout_duration');
$maxLoginAttempts = config('auth.passwords.users.throttle.max_attempts');
return $this->limiter()->tooManyAttempts(
$this->throttleKey($request),
$maxLoginAttempts,
$lockoutTime
);
}
public function legacyAuthRedirect()
{

View File

@@ -71,20 +71,28 @@ class BulkAssetModelsController extends Controller
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id') != 'NC'))) {
$update_array['manufacturer_id'] = $request->input('manufacturer_id');
}
if (($request->filled('category_id') && ($request->input('category_id') != 'NC'))) {
$update_array['category_id'] = $request->input('category_id');
}
if ($request->input('fieldset_id') != 'NC') {
$update_array['fieldset_id'] = $request->input('fieldset_id');
}
if ($request->input('depreciation_id') != 'NC') {
$update_array['depreciation_id'] = $request->input('depreciation_id');
}
if ($request->filled('requestable') != '') {
if ($request->input('requestable') != '') {
$update_array['requestable'] = $request->input('requestable');
}
if ($request->filled('min_amt')) {
$update_array['min_amt'] = $request->input('min_amt');
}
if (count($update_array) > 0) {
AssetModel::whereIn('id', $models_raw_array)->update($update_array);

View File

@@ -83,29 +83,30 @@ class CustomFieldsController extends Controller
{
$this->authorize('create', CustomField::class);
$show_in_email = $request->get("show_in_email", 0);
$display_in_user_view = $request->get("display_in_user_view", 0);
$show_in_email = $request->input("show_in_email", 0);
$display_in_user_view = $request->input("display_in_user_view", 0);
// Override the display settings if the field is encrypted
if ($request->get("field_encrypted") == '1') {
if ($request->input("field_encrypted") == '1') {
$show_in_email = '0';
$display_in_user_view = '0';
}
$field = new CustomField([
"name" => trim($request->get("name")),
"element" => $request->get("element"),
"help_text" => $request->get("help_text"),
"field_values" => $request->get("field_values"),
"field_encrypted" => $request->get("field_encrypted", 0),
"name" => trim($request->input("name")),
"element" => $request->input("element"),
"help_text" => $request->input("help_text"),
"field_values" => $request->input("field_values"),
"field_encrypted" => $request->input("field_encrypted", 0),
"show_in_email" => $show_in_email,
"is_unique" => $request->get("is_unique", 0),
"is_unique" => $request->input("is_unique", 0),
"display_in_user_view" => $display_in_user_view,
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
"show_in_listview" => $request->get("show_in_listview", 0),
"show_in_requestable_list" => $request->get("show_in_requestable_list", 0),
"display_checkin" => $request->get("display_checkin", 0),
"display_checkout" => $request->get("display_checkout", 0),
"auto_add_to_fieldsets" => $request->input("auto_add_to_fieldsets", 0),
"show_in_listview" => $request->input("show_in_listview", 0),
"show_in_requestable_list" => $request->input("show_in_requestable_list", 0),
"display_checkin" => $request->input("display_checkin", 0),
"display_checkout" => $request->input("display_checkout", 0),
"display_audit" => $request->input("display_audit", 0),
"created_by" => auth()->id()
]);
@@ -237,8 +238,8 @@ class CustomFieldsController extends Controller
$display_in_user_view = '0';
}
$field->name = trim(e($request->get("name")));
$field->element = e($request->get("element"));
$field->name = trim($request->get("name"));
$field->element = $request->get("element");
$field->field_values = $request->get("field_values");
$field->created_by = auth()->id();
$field->help_text = $request->get("help_text");
@@ -250,11 +251,12 @@ class CustomFieldsController extends Controller
$field->show_in_requestable_list = $request->get("show_in_requestable_list", 0);
$field->display_checkin = $request->get("display_checkin", 0);
$field->display_checkout = $request->get("display_checkout", 0);
$field->display_audit = $request->get("display_audit", 0);
if ($request->get('format') == 'CUSTOM REGEX') {
$field->format = e($request->get('custom_format'));
$field->format = $request->get('custom_format');
} else {
$field->format = e($request->get('format'));
$field->format = $request->get('format');
}
if ($field->element == 'checkbox' || $field->element == 'radio'){

View File

@@ -40,7 +40,7 @@ class DashboardController extends Controller
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--force' => true]);
\Artisan::call('passport:install');
Artisan::call('passport:install', ['--no-interaction' => true]);
}
return view('dashboard')->with('asset_stats', $asset_stats)->with('counts', $counts);

View File

@@ -83,6 +83,10 @@ class GroupsController extends Controller
{
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
if ((!is_array($groupPermissions)) || (!$groupPermissions)) {
$groupPermissions = [];
}
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}

View File

@@ -38,6 +38,7 @@ class LabelsController extends Controller
$exampleAsset->order_number = '12345';
$exampleAsset->purchase_date = '2023-01-01';
$exampleAsset->status_id = 1;
$exampleAsset->location_id = 1;
$exampleAsset->company = new Company([
'name' => trans('admin/labels/table.example_company'),

View File

@@ -87,6 +87,7 @@ class LicenseCheckinController extends Controller
if($licenseSeat->assigned_to != null){
$return_to = User::find($licenseSeat->assigned_to);
session()->put('checkedInFrom', $return_to->id);
} else {
$return_to = Asset::find($licenseSeat->asset_id);
}

View File

@@ -2,10 +2,13 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Location;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
@@ -63,6 +66,7 @@ class LocationsController extends Controller
public function store(ImageUploadRequest $request) : RedirectResponse
{
$this->authorize('create', Location::class);
$location = new Location();
$location->name = $request->input('name');
$location->parent_id = $request->input('parent_id', null);
@@ -79,6 +83,18 @@ class LocationsController extends Controller
$location->phone = request('phone');
$location->fax = request('fax');
$location->notes = $request->input('notes');
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
// Only scope the location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
// check if parent is set and has a different company
if ($location->parent_id && Location::find($location->parent_id)->company_id != $location->company_id) {
return redirect()->back()->withInput()->withInput()->with('error', 'different company than parent');
}
} else {
$location->company_id = $request->input('company_id');
}
$location = $request->handleImages($location);
@@ -100,7 +116,7 @@ class LocationsController extends Controller
public function edit(Location $location) : View | RedirectResponse
{
$this->authorize('update', Location::class);
return view('locations/edit');
return view('locations/edit')->with('item', $location);
}
/**
@@ -131,6 +147,17 @@ class LocationsController extends Controller
$location->manager_id = $request->input('manager_id');
$location->notes = $request->input('notes');
// Only scope the location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
// check if there are related objects with different company
if (Helper::test_locations_fmcs(false, $location->id, $location->company_id)) {
return redirect()->back()->withInput()->withInput()->with('error', 'error scoped locations');
}
} else {
$location->company_id = $request->input('company_id');
}
$location = $request->handleImages($location);
if ($location->save()) {
@@ -150,6 +177,7 @@ class LocationsController extends Controller
public function destroy($locationId) : RedirectResponse
{
$this->authorize('delete', Location::class);
if (is_null($location = Location::find($locationId))) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
}
@@ -186,6 +214,8 @@ class LocationsController extends Controller
*/
public function show(Location $location) : View | RedirectResponse
{
$this->authorize('view', Location::class);
$location = Location::withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('rtd_assets as rtd_assets_count')
@@ -203,20 +233,24 @@ class LocationsController extends Controller
public function print_assigned($id) : View | RedirectResponse
{
$this->authorize('view', Location::class);
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$company = Company::where('id', $location->company_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
return view('locations/print')
->with('assets', $assets)
->with('users',$users)
->with('location', $location)
->with('parent', $parent)
->with('manager', $manager)
->with('company', $company);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
@@ -285,13 +319,20 @@ class LocationsController extends Controller
}
public function print_all_assigned($id) : View | RedirectResponse
{
$this->authorize('view', Location::class);
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$company = Company::where('id', $location->company_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
return view('locations/print')
->with('assets', $assets)
->with('users',$users)
->with('location', $location)
->with('parent', $parent)
->with('manager', $manager)
->with('company', $company);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
@@ -305,6 +346,8 @@ class LocationsController extends Controller
*/
public function postBulkDelete(Request $request) : View | RedirectResponse
{
$this->authorize('update', Location::class);
$locations_raw_array = $request->input('ids');
// Make sure some IDs have been selected
@@ -338,6 +381,8 @@ class LocationsController extends Controller
*/
public function postBulkDeleteStore(Request $request) : RedirectResponse
{
$this->authorize('delete', Location::class);
$locations_raw_array = $request->input('ids');
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {

View File

@@ -0,0 +1,111 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\StorageHelper;
use App\Http\Requests\UploadFileRequest;
use App\Models\Actionlog;
use App\Models\Location;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use \Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class LocationsFilesController extends Controller
{
/**
* Upload a file to the server.
*
* @param UploadFileRequest $request
* @param int $modelId
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*@since [v1.0]
* @author [A. Gianotto] [<snipe@snipe.net>]
*/
public function store(UploadFileRequest $request, Location $location) : RedirectResponse
{
$this->authorize('update', $location);
if ($request->hasFile('file')) {
if (! Storage::exists('private_uploads/locations')) {
Storage::makeDirectory('private_uploads/locations', 775);
}
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/locations/','location-'.$location->id, $file);
$location->logUpload($file_name, $request->get('notes'));
}
return redirect()->back()->withFragment('files')->with('success', trans('general.file_upload_success'));
}
return redirect()->back()->withFragment('files')->with('error', trans('admin/hardware/message.upload.nofiles'));
}
/**
* Check for permissions and display the file.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $modelId
* @param int $fileId
* @since [v1.0]
*/
public function show(Location $location, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
{
$this->authorize('view', $location);
if (! $log = Actionlog::find($fileId)) {
return redirect()->back()->withFragment('files')->with('error', 'No matching file record');
}
$file = 'private_uploads/locations/'.$log->filename;
if (! Storage::exists($file)) {
return redirect()->back()->withFragment('files')->with('error', 'No matching file on server');
}
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
return StorageHelper::downloader($file);
}
/**
* Delete the associated file
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $modelId
* @param int $fileId
* @since [v1.0]
*/
public function destroy(Location $location, $fileId = null) : RedirectResponse
{
$rel_path = 'private_uploads/locations';
$this->authorize('update', $location);
$log = Actionlog::find($fileId);
if ($log) {
// This should be moved to purge
// if (Storage::exists($rel_path.'/'.$log->filename)) {
// Storage::delete($rel_path.'/'.$log->filename);
// }
$log->delete();
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
}
}

View File

@@ -6,6 +6,7 @@ use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Manufacturer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
@@ -31,7 +32,30 @@ class ManufacturersController extends Controller
public function index() : View
{
$this->authorize('index', Manufacturer::class);
return view('manufacturers/index');
$manufacturer_count = Manufacturer::withTrashed()->count();
return view('manufacturers/index')->with('manufacturer_count', $manufacturer_count);
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the manufacturers listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see Api\ManufacturersController::index() method that generates the JSON response
* @since [v1.0]
*/
public function seed() : RedirectResponse
{
$this->authorize('index', Manufacturer::class);
$manufacturers_count = Manufacturer::withTrashed()->count();
if ($manufacturers_count == 0) {
Artisan::call('db:seed', ['--class' => 'ManufacturerSeeder']);
return redirect()->route('manufacturers.index')->with('success', trans('general.seeding.manufacturers.success'));
}
return redirect()->route('manufacturers.index')->with('error', trans_choice('general.seeding.manufacturers.error', ['count' => $manufacturers_count]));
}
/**

View File

@@ -41,10 +41,11 @@ class ModalController extends Controller
$view = view("modals.${type}");
if ($type == "statuslabel") {
$view->with('statuslabel_types', Helper::statusTypeList());
}
if (in_array($type, ['kit-model', 'kit-license', 'kit-consumable', 'kit-accessory'])) {
$view->with('kitId', $itemId);
$view->with('statuslabel_types', Helper::statusTypeList());
}
if (in_array($type, ['kit-model', 'kit-license', 'kit-consumable', 'kit-accessory'])) {
$view->with('kitId', $itemId);
}
return $view;
}

View File

@@ -53,7 +53,7 @@ class ProfileController extends Controller
$user->enable_confetti = $request->input('enable_confetti', false);
if (! config('app.lock_passwords')) {
$user->locale = $request->input('locale', 'en-US');
$user->locale = $request->input('locale');
}
if ((Gate::allows('self.two_factor')) && ((Setting::getSettings()->two_factor_enabled == '1') && (! config('app.lock_passwords')))) {
@@ -136,7 +136,7 @@ class ProfileController extends Controller
}
// This checks to make sure that the user's password isn't the same as their username,
// email address, first name or last name (see https://github.com/snipe/snipe-it/issues/8661)
// email address, first name or last name (see https://github.com/grokability/snipe-it/issues/8661)
// While this is handled via SaveUserRequest form request in other places, we have to do this manually
// here because we don't have the username, etc form fields available in the profile password change
// form.

View File

@@ -243,7 +243,7 @@ class ReportsController extends Controller
$header = [
trans('general.date'),
trans('general.admin'),
trans('general.created_by'),
trans('general.action'),
trans('general.type'),
trans('general.item'),
@@ -266,7 +266,7 @@ class ReportsController extends Controller
$actionlogs = Actionlog::with('item', 'user', 'target', 'location', 'adminuser')
->orderBy('created_at', 'DESC')
->chunk(20, function ($actionlogs) use ($handle) {
->chunk(500, function ($actionlogs) use ($handle) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
Log::debug('Walking results: '.$executionTime);
$count = 0;
@@ -485,7 +485,7 @@ class ReportsController extends Controller
$header[] = trans('admin/hardware/table.purchase_date');
}
if (($request->filled('purchase_cost')) || ($request->filled('depreciation'))) {
if ($request->filled('purchase_cost')) {
$header[] = trans('admin/hardware/table.purchase_cost');
}
@@ -493,6 +493,17 @@ class ReportsController extends Controller
$header[] = trans('admin/hardware/table.eol');
}
if ($request->filled('warranty')) {
$header[] = trans('admin/hardware/form.warranty');
$header[] = trans('admin/hardware/form.warranty_expires');
}
if ($request->filled('depreciation')) {
$header[] = trans('admin/hardware/table.book_value');
$header[] = trans('admin/hardware/table.diff');
$header[] = trans('admin/hardware/form.fully_depreciated');
}
if ($request->filled('order')) {
$header[] = trans('admin/hardware/form.order');
}
@@ -579,17 +590,6 @@ class ReportsController extends Controller
$header[] = trans('general.status');
}
if ($request->filled('warranty')) {
$header[] = trans('admin/hardware/form.warranty');
$header[] = trans('admin/hardware/form.warranty_expires');
}
if ($request->filled('depreciation')) {
$header[] = trans('admin/hardware/table.book_value');
$header[] = trans('admin/hardware/table.diff');
$header[] = trans('admin/hardware/form.fully_depreciated');
}
if ($request->filled('checkout_date')) {
$header[] = trans('admin/hardware/table.checkout_date');
}
@@ -748,7 +748,7 @@ class ReportsController extends Controller
}
Log::debug($assets->toSql());
$assets->orderBy('assets.id', 'ASC')->chunk(20, function ($assets) use ($handle, $customfields, $request) {
$assets->orderBy('assets.id', 'ASC')->chunk(500, function ($assets) use ($handle, $customfields, $request) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
Log::debug('Walking results: '.$executionTime);
@@ -805,6 +805,19 @@ class ReportsController extends Controller
$row[] = ($asset->purchase_date != '') ? $asset->asset_eol_date : '';
}
if ($request->filled('warranty')) {
$row[] = ($asset->warranty_months) ? $asset->warranty_months : '';
$row[] = $asset->present()->warranty_expires();
}
if ($request->filled('depreciation')) {
$depreciation = $asset->getDepreciatedValue();
$diff = ($asset->purchase_cost - $depreciation);
$row[] = Helper::formatCurrencyOutput($depreciation);
$row[] = Helper::formatCurrencyOutput($diff);
$row[] = (($asset->depreciation) && ($asset->depreciated_date())) ? $asset->depreciated_date()->format('Y-m-d') : '';
}
if ($request->filled('order')) {
$row[] = ($asset->order_number) ? $asset->order_number : '';
}
@@ -938,19 +951,6 @@ class ReportsController extends Controller
$row[] = ($asset->assetstatus) ? $asset->assetstatus->name.' ('.$asset->present()->statusMeta.')' : '';
}
if ($request->filled('warranty')) {
$row[] = ($asset->warranty_months) ? $asset->warranty_months : '';
$row[] = $asset->present()->warranty_expires();
}
if ($request->filled('depreciation')) {
$depreciation = $asset->getDepreciatedValue();
$diff = ($asset->purchase_cost - $depreciation);
$row[] = Helper::formatCurrencyOutput($depreciation);
$row[] = Helper::formatCurrencyOutput($diff);
$row[] = (($asset->depreciation) && ($asset->depreciated_date())) ? $asset->depreciated_date()->format('Y-m-d') : '';
}
if ($request->filled('checkout_date')) {
$row[] = ($asset->last_checkout) ? $asset->last_checkout : '';
}
@@ -1081,10 +1081,10 @@ class ReportsController extends Controller
$row[] = e($assetMaintenance->start_date);
$row[] = e($assetMaintenance->completion_date);
if (is_null($assetMaintenance->asset_maintenance_time)) {
$improvementTime = intval(Carbon::now()
->diffInDays(Carbon::parse($assetMaintenance->start_date)));
$improvementTime = (int) Carbon::now()
->diffInDays(Carbon::parse($assetMaintenance->start_date), true);
} else {
$improvementTime = intval($assetMaintenance->asset_maintenance_time);
$improvementTime = (int) $assetMaintenance->asset_maintenance_time;
}
$row[] = $improvementTime;
$row[] = trans('general.currency') . Helper::formatCurrencyOutput($assetMaintenance->cost);
@@ -1175,18 +1175,13 @@ class ReportsController extends Controller
}
$email = $assetItem->assignedTo?->email;
$locale = $assetItem->assignedTo?->locale;
// Only send notification if assigned
if ($locale && $email) {
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note))->locale($locale));
} elseif ($email) {
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)));
}
if ($email == ''){
if (is_null($email) || $email === '') {
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_email'));
}
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note, firstTimeSending: false))->locale($locale));
return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent'));
}

32
app/Http/Controllers/SettingsController.php Executable file → Normal file
View File

@@ -14,6 +14,7 @@ use App\Http\Requests\StoreLabelSettings;
use App\Http\Requests\StoreSecuritySettings;
use App\Models\CustomField;
use App\Models\Group;
use App\Models\Labels\Label as LabelModel;
use App\Models\Setting;
use App\Models\Asset;
use App\Models\User;
@@ -256,7 +257,7 @@ class SettingsController extends Controller
Artisan::call('migrate', ['--force' => true]);
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
Artisan::call('passport:install');
Artisan::call('passport:install', ['--no-interaction' => true]);
}
return view('setup/migrate')
@@ -290,7 +291,6 @@ class SettingsController extends Controller
public function getSettings() : View
{
$setting = Setting::getSettings();
return view('settings/general', compact('setting'));
}
@@ -314,7 +314,23 @@ class SettingsController extends Controller
$setting->modellist_displays = implode(',', $request->input('show_in_model_list'));
}
$old_locations_fmcs = $setting->scope_locations_fmcs;
$setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0');
$setting->scope_locations_fmcs = $request->input('scope_locations_fmcs', '0');
// Backward compatibility for locations makes no sense without FullMultipleCompanySupport
if (!$setting->full_multiple_companies_support) {
$setting->scope_locations_fmcs = '0';
}
// check for inconsistencies when activating scoped locations
if ($old_locations_fmcs == '0' && $setting->scope_locations_fmcs == '1') {
$mismatched = Helper::test_locations_fmcs(false);
if (count($mismatched) != 0) {
return redirect()->back()->withInput()->with('error', trans_choice('admin/settings/message.location_scoping.mismatch', count($mismatched)).' '.trans('admin/settings/message.location_scoping.not_saved'));
}
}
$setting->unique_serial = $request->input('unique_serial', '0');
$setting->shortcuts_enabled = $request->input('shortcuts_enabled', '0');
$setting->show_images_in_email = $request->input('show_images_in_email', '0');
@@ -428,6 +444,13 @@ class SettingsController extends Controller
$setting->label_logo = null;
}
// Acceptance PDF upload
$setting = $request->handleImages($setting, 600, 'acceptance_pdf_logo', '', 'acceptance_pdf_logo');
if ('1' == $request->input('clear_acceptance_pdf_logo')) {
$setting = $request->deleteExistingImage($setting, '', 'acceptance_pdf_logo');
$setting->acceptance_pdf_logo = null;
}
// Favicon upload
$setting = $request->handleImages($setting, 100, 'favicon', '', 'favicon');
if ('1' == $request->input('clear_favicon')) {
@@ -435,6 +458,7 @@ class SettingsController extends Controller
$setting->favicon = null;
}
// Default avatar upload
$setting = $request->handleImages($setting, 500, 'default_avatar', 'avatars', 'default_avatar');
if ($request->input('clear_default_avatar') == '1') {
@@ -748,6 +772,7 @@ class SettingsController extends Controller
$setting->label2_2d_type = $request->input('label2_2d_type');
$setting->label2_2d_target = $request->input('label2_2d_target');
$setting->label2_fields = $request->input('label2_fields');
$setting->label2_empty_row_count = $request->input('label2_empty_row_count');
$setting->labels_per_page = $request->input('labels_per_page');
$setting->labels_width = $request->input('labels_width');
$setting->labels_height = $request->input('labels_height');
@@ -850,7 +875,8 @@ class SettingsController extends Controller
$setting->ldap_fname_field = $request->input('ldap_fname_field');
$setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query');
$setting->ldap_version = $request->input('ldap_version', 3);
$setting->ldap_active_flag = $request->input('ldap_active_flag');
$setting->ldap_active_flag = $request->input('ldap_active_flag', 0);
$setting->ldap_invert_active_flag = $request->input('ldap_invert_active_flag', 0);
$setting->ldap_emp_num = $request->input('ldap_emp_num');
$setting->ldap_email = $request->input('ldap_email');
$setting->ldap_manager = $request->input('ldap_manager');

View File

@@ -298,7 +298,6 @@ class BulkUsersController extends Controller
$this->logItemCheckinAndDelete($assets, Asset::class);
$this->logAccessoriesCheckin($accessoryUserRows);
$this->logItemCheckinAndDelete($licenses, License::class);
$this->logConsumablesCheckin($consumableUserRows);
Asset::whereIn('id', $assets->pluck('id'))->update([
'status_id' => e(request('status_id')),
@@ -360,21 +359,7 @@ class BulkUsersController extends Controller
$logAction->item_type = Accessory::class;
$logAction->target_id = $accessoryUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}
}
private function logConsumablesCheckin(Collection $consumableUserRows): void
{
foreach ($consumableUserRows as $consumableUserRow) {
$logAction = new Actionlog();
$logAction->item_id = $consumableUserRow->consumable_id;
$logAction->item_type = Consumable::class;
$logAction->target_id = $consumableUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->created_at = auth()->id();
$logAction->created_by = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}

View File

@@ -198,10 +198,9 @@ class UsersController extends Controller
$userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions);
$permissions = $this->filterDisplayable($permissions);
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'));
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user);
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
}
/**
@@ -396,13 +395,22 @@ class UsersController extends Controller
// Make sure the user can view users at all
$this->authorize('view', User::class);
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($user->id);
$user = User::with([
'consumables',
'accessories',
'licenses',
'userloc',
])
->withTrashed()
->find($user->id);
// Make sure they can view this particular user
$this->authorize('view', $user);
$userlog = $user->userlog->load('item');
return view('users/view', compact('user', 'userlog'))->with('settings', Setting::getSettings());
return view('users/view', [
'user' => $user,
'settings' => Setting::getSettings(),
]);
}
@@ -456,10 +464,10 @@ class UsersController extends Controller
->with('user', $user)
->with('groups', Group::pluck('name', 'id'))
->with('userGroups', $userGroups)
->with('clone_user', $user_to_clone);
->with('clone_user', $user_to_clone)
->with('item', $user);
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
}
@@ -586,18 +594,18 @@ class UsersController extends Controller
$user = User::where('id', $id)
->with([
'assets.assetlog',
'assets.assignedAssets.assetlog',
'assets.log' => fn($query) => $query->withTrashed()->where('target_type', User::class)->where('target_id', $id)->where('action_type', 'accepted'),
'assets.assignedAssets.log' => fn($query) => $query->withTrashed()->where('target_type', User::class)->where('target_id', $id)->where('action_type', 'accepted'),
'assets.assignedAssets.defaultLoc',
'assets.assignedAssets.location',
'assets.assignedAssets.model.category',
'assets.defaultLoc',
'assets.location',
'assets.model.category',
'accessories.assetlog',
'accessories.log' => fn($query) => $query->withTrashed()->where('target_type', User::class)->where('target_id', $id)->where('action_type', 'accepted'),
'accessories.category',
'accessories.manufacturer',
'consumables.assetlog',
'consumables.log' => fn($query) => $query->withTrashed()->where('target_type', User::class)->where('target_id', $id)->where('action_type', 'accepted'),
'consumables.category',
'consumables.manufacturer',
'licenses.category',

View File

@@ -2,18 +2,21 @@
namespace App\Http\Controllers;
use App\Actions\CheckoutRequests\CancelCheckoutRequestAction;
use App\Actions\CheckoutRequests\CreateCheckoutRequestAction;
use App\Exceptions\AssetNotRequestable;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\RequestAssetCancelation;
use App\Notifications\RequestAssetNotification;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View;
use Log;
use Exception;
/**
* This controller handles all actions related to the ability for users
@@ -81,7 +84,7 @@ class ViewAssetsController extends Controller
return view('account/requestable-assets', compact('assets', 'models'));
}
public function getRequestItem(Request $request, $itemType, $itemId = null, $cancel_by_admin = false, $requestingUser = null) : RedirectResponse
public function getRequestItem(Request $request, $itemType, $itemId = null, $cancel_by_admin = false, $requestingUser = null): RedirectResponse
{
$item = null;
$fullItemType = 'App\\Models\\'.studly_case($itemType);
@@ -144,63 +147,33 @@ class ViewAssetsController extends Controller
* Process a specific requested asset
* @param null $assetId
*/
public function getRequestAsset($assetId = null) : RedirectResponse
public function store(Asset $asset): RedirectResponse
{
$user = auth()->user();
// Check if the asset exists and is requestable
if (is_null($asset = Asset::RequestableAssets()->find($assetId))) {
return redirect()->route('requestable-assets')
->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
}
if (! Company::isCurrentUserHasAccess($asset)) {
return redirect()->route('requestable-assets')
->with('error', trans('general.insufficient_permissions'));
}
$data['item'] = $asset;
$data['target'] = auth()->user();
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id;
$logaction->item_type = $data['item_type'] = Asset::class;
$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
if ($user->location_id) {
$logaction->location_id = $user->location_id;
}
$logaction->target_id = $data['user_id'] = auth()->id();
$logaction->target_type = User::class;
// If it's already requested, cancel the request.
if ($asset->isRequestedBy(auth()->user())) {
$asset->cancelRequest();
$asset->decrement('requests_counter', 1);
$logaction->logaction('request canceled');
try {
$settings->notify(new RequestAssetCancelation($data));
} catch (\Exception $e) {
Log::warning($e);
}
return redirect()->route('requestable-assets')
->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
}
$logaction->logaction('requested');
$asset->request();
$asset->increment('requests_counter', 1);
try {
$settings->notify(new RequestAssetNotification($data));
} catch (\Exception $e) {
Log::warning($e);
CreateCheckoutRequestAction::run($asset, auth()->user());
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
} catch (AssetNotRequestable $e) {
return redirect()->back()->with('error', 'Asset is not requestable');
} catch (AuthorizationException $e) {
return redirect()->back()->with('error', trans('admin/hardware/message.requests.error'));
} catch (Exception $e) {
report($e);
return redirect()->back()->with('error', trans('general.something_went_wrong'));
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
}
public function destroy(Asset $asset): RedirectResponse
{
try {
CancelCheckoutRequestAction::run($asset, auth()->user());
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
} catch (Exception $e) {
report($e);
return redirect()->back()->with('error', trans('general.something_went_wrong'));
}
}
public function getRequestedAssets() : View
{
return view('account/requested');

View File

@@ -33,9 +33,9 @@ class SaveUserRequest extends FormRequest
public function rules()
{
$rules = [
'department_id' => 'nullable|exists:departments,id',
'department_id' => 'nullable|integer|exists:departments,id',
'manager_id' => 'nullable|exists:users,id',
'company_id' => ['nullable','exists:companies,id']
'company_id' => ['nullable', 'integer', 'exists:companies,id']
];
switch ($this->method()) {

View File

@@ -39,7 +39,6 @@ class StoreAssetRequest extends ImageUploadRequest
$this->merge([
'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(),
'company_id' => $idForCurrentUser,
'assigned_to' => $assigned_to ?? null,
]);
}

View File

@@ -29,6 +29,12 @@ class StoreLabelSettings extends FormRequest
return $label->getName();
})->values()->toArray();
if (empty($this->input('label2_template'))) {
$this->merge([
'label2_template' => 'DefaultLabel',
]);
}
return [
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',

View File

@@ -27,8 +27,6 @@ class StoreLdapSettings extends FormRequest
'ldap_auth_filter_query' => 'not_in:uid=samaccountname|required_if:ldap_enabled,1',
'ldap_filter' => 'nullable|regex:"^[^(]"|required_if:ldap_enabled,1',
'ldap_server' => 'nullable|required_if:ldap_enabled,1|starts_with:ldap://,ldaps://',
'ldap_uname' => 'nullable|required_if:ldap_enabled,1',
'ldap_pword' => 'nullable|required_if:ldap_enabled,1',
'ldap_basedn' => 'nullable|required_if:ldap_enabled,1',
'ldap_fname_field' => 'nullable|required_if:ldap_enabled,1',
'custom_forgot_pass_url' => 'nullable|url',

View File

@@ -26,9 +26,9 @@ class StoreNotificationSettings extends FormRequest
return [
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email_array|nullable',
'alert_threshold' => 'numeric|nullable|gt:0',
'alert_threshold' => 'numeric|nullable',
'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable',
'due_checkin_days' => 'numeric|nullable|gt:0',
'audit_interval' => 'numeric|nullable|gt:0',
];

View File

@@ -10,19 +10,36 @@ trait MayContainCustomFields
// this gets called automatically on a form request
public function withValidator($validator)
{
// find the model
if ($this->method() == 'POST') {
$asset_model = AssetModel::find($this->model_id);
}
if ($this->method() == 'PATCH' || $this->method() == 'PUT') {
$asset_model = $this->asset->model;
// In case the model is being changed via form
if (request()->has('model_id')!='') {
$asset_model = AssetModel::find(request()->input('model_id'));
// or if we have it available to route-model-binding
} elseif ((request()->route('asset') && (request()->route('asset')->model_id))) {
$asset_model = AssetModel::find(request()->route('asset')->model_id);
} else {
if ($this->method() == 'POST') {
$asset_model = AssetModel::find($this->model_id);
}
if ($this->method() == 'PATCH' || $this->method() == 'PUT') {
$asset_model = $this->asset->model;
}
}
// collect the custom fields in the request
$validator->after(function ($validator) use ($asset_model) {
$request_fields = $this->collect()->keys()->filter(function ($attributes) {
return str_starts_with($attributes, '_snipeit_');
});
// if there are custom fields, find the one's that don't exist on the model's fieldset and add an error to the validator's error bag
// if there are custom fields, find the ones that don't exist on the model's fieldset and add an error to the validator's error bag
if (count($request_fields) > 0 && $validator->errors()->isEmpty()) {
$request_fields->diff($asset_model?->fieldset?->fields?->pluck('db_column'))
->each(function ($request_field_name) use ($request_fields, $validator) {

View File

@@ -37,8 +37,10 @@ class AccessoriesTransformer
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => (int) ($accessory->qty - $accessory->checkouts_count),
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, // Legacy - should phase out - replaced by below, for the bootstrap table formatter
'min_amt' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => (int) ($accessory->qty - $accessory->checkouts_count), // Legacy - should phase out - replaced by below, for the bootstrap table formatter
'remaining' => (int) ($accessory->qty - $accessory->checkouts_count),
'checkouts_count' => $accessory->checkouts_count,
'created_by' => ($accessory->adminuser) ? [
'id' => (int) $accessory->adminuser->id,
@@ -53,7 +55,7 @@ class AccessoriesTransformer
'checkout' => Gate::allows('checkout', Accessory::class),
'checkin' => false,
'update' => Gate::allows('update', Accessory::class),
'delete' => Gate::allows('delete', Accessory::class),
'delete' => $accessory->checkouts_count === 0 && Gate::allows('delete', Accessory::class),
'clone' => Gate::allows('create', Accessory::class),
];
@@ -92,6 +94,10 @@ class AccessoriesTransformer
public function transformAssignedTo($accessoryCheckout)
{
if (is_null($accessoryCheckout->assigned)) {
return null;
}
if ($accessoryCheckout->checkedOutToUser()) {
return (new UsersTransformer)->transformUserCompact($accessoryCheckout->assigned);
} elseif ($accessoryCheckout->checkedOutToLocation()) {

View File

@@ -46,8 +46,9 @@ class AssetModelsTransformer
'name'=> e($assetmodel->manufacturer->name),
] : null,
'image' => ($assetmodel->image != '') ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null,
'model_number' => e($assetmodel->model_number),
'model_number' => ($assetmodel->model_number ? e($assetmodel->model_number): null),
'min_amt' => ($assetmodel->min_amt) ? (int) $assetmodel->min_amt : null,
'remaining' => (int) ($assetmodel->assets_count - $assetmodel->min_amt),
'depreciation' => ($assetmodel->depreciation) ? [
'id' => (int) $assetmodel->depreciation->id,
'name'=> e($assetmodel->depreciation->name),
@@ -104,6 +105,7 @@ class AssetModelsTransformer
$array = [
'id' => (int) $file->id,
'filename' => e($file->filename),
'note' => $file->note,
'url' => route('show/modelfile', [$assetmodel->id, $file->id]),
'created_by' => ($file->adminuser) ? [
'id' => (int) $file->adminuser->id,

View File

@@ -42,7 +42,7 @@ class AssetsTransformer
'requestable' => ($asset->requestable ? true : false),
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => (($asset->asset_eol_date != '') && ($asset->purchase_date != '')) ? Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date).' months' : null,
'eol' => (($asset->asset_eol_date != '') && ($asset->purchase_date != '')) ? (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true) . ' months' : null,
'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
@@ -155,6 +155,7 @@ class AssetsTransformer
'clone' => Gate::allows('create', Asset::class) ? true : false,
'restore' => ($asset->deleted_at!='' && Gate::allows('create', Asset::class)) ? true : false,
'update' => ($asset->deleted_at=='' && Gate::allows('update', Asset::class)) ? true : false,
'audit' => Gate::allows('audit', Asset::class) ? true : false,
'delete' => ($asset->deleted_at=='' && $asset->assigned_to =='' && Gate::allows('delete', Asset::class) && ($asset->deleted_at == '')) ? true : false,
];
@@ -302,30 +303,32 @@ class AssetsTransformer
public function transformCheckedoutAccessory(AccessoryCheckout $accessory_checkout)
{
if ($accessory_checkout->accessory) {
$array = [
'id' => $accessory_checkout->id,
'accessory' => [
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,
],
'assigned_to' => $accessory_checkout->assigned_to,
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/' . e($accessory_checkout->accessory->image)) : null,
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
'created_by' => $accessory_checkout->adminuser ? [
'id' => (int)$accessory_checkout->adminuser->id,
'name' => e($accessory_checkout->adminuser->present()->fullName),
] : null,
'created_at' => Helper::getFormattedDateObject($accessory_checkout->created_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($accessory_checkout->deleted_at, 'datetime'),
];
$array = [
'id' => $accessory_checkout->id,
'accessory' => [
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,
],
'assigned_to' => $accessory_checkout->assigned_to,
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory_checkout->accessory->image)) : null,
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
'created_by' => $accessory_checkout->adminuser ? [
'id' => (int) $accessory_checkout->adminuser->id,
'name'=> e($accessory_checkout->adminuser->present()->fullName),
]: null,
'created_at' => Helper::getFormattedDateObject($accessory_checkout->created_at, 'datetime'),
];
$permissions_array['available_actions'] = [
'checkout' => false,
'checkin' => Gate::allows('checkin', Accessory::class),
];
$permissions_array['available_actions'] = [
'checkout' => false,
'checkin' => Gate::allows('checkin', Accessory::class),
];
$array += $permissions_array;
return $array;
$array += $permissions_array;
return $array;
}
}
}

View File

@@ -50,6 +50,9 @@ class CustomFieldsTransformer
'display_in_user_view' => ($field->display_in_user_view =='1') ? true : false,
'auto_add_to_fieldsets' => ($field->auto_add_to_fieldsets == '1') ? true : false,
'show_in_listview' => ($field->show_in_listview == '1') ? true : false,
'display_checkin' => ($field->display_checkin == '1') ? true : false,
'display_checkout' => ($field->display_checkout == '1') ? true : false,
'display_audit' => ($field->display_audit == '1') ? true : false,
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
];

View File

@@ -24,7 +24,7 @@ class GroupsTransformer
$array = [
'id' => (int) $group->id,
'name' => e($group->name),
'permissions' => json_decode($group->permissions),
'permissions' => $group->decodePermissions(),
'users_count' => (int) $group->users_count,
'notes' => Helper::parseEscapedMarkedownInline($group->notes),
'created_by' => ($group->adminuser) ? [

View File

@@ -2,6 +2,7 @@
namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\License;
use App\Models\LicenseSeat;
use Illuminate\Support\Facades\Gate;
@@ -26,6 +27,7 @@ class LicenseSeatsTransformer
$array = [
'id' => (int) $seat->id,
'license_id' => (int) $seat->license->id,
'updated_at' => Helper::getFormattedDateObject($seat->updated_at, 'datetime'), // we use updated_at here because the record gets updated when it's checked in or out
'assigned_user' => ($seat->user) ? [
'id' => (int) $seat->user->id,
'name'=> e($seat->user->present()->fullName),
@@ -36,14 +38,17 @@ class LicenseSeatsTransformer
'name' => e($seat->user->department->name),
] : null,
'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'),
] : null,
'assigned_asset' => ($seat->asset) ? [
'id' => (int) $seat->asset->id,
'name'=> e($seat->asset->present()->fullName),
'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'),
] : null,
'location' => ($seat->location()) ? [
'id' => (int) $seat->location()->id,
'name'=> e($seat->location()->name),
'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'),
] : null,
'reassignable' => (bool) $seat->license->reassignable,
'notes' => e($seat->notes),

View File

@@ -38,6 +38,7 @@ class LicensesTransformer
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'seats' => (int) $license->seats,
'free_seats_count' => (int) $license->free_seats_count,
'remaining' => (int) $license->free_seats_count,
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
'license_name' => ($license->license_name) ? e($license->license_name) : null,
'license_email' => ($license->license_email) ? e($license->license_email) : null,

View File

@@ -63,6 +63,10 @@ class LocationsTransformer
'name'=> e($location->parent->name),
] : null,
'manager' => ($location->manager) ? (new UsersTransformer)->transformUser($location->manager) : null,
'company' => ($location->company) ? [
'id' => (int) $location->company->id,
'name'=> e($location->company->name)
] : null,
'children' => $children_arr,
];
@@ -101,11 +105,8 @@ class LocationsTransformer
$array = [
'id' => $accessory_checkout->id,
'assigned_to' => $accessory_checkout->assigned_to,
'accessory' => [
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,
],
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory_checkout->accessory->image)) : null,
'accessory' => $this->transformAccessory($accessory_checkout->accessory),
'image' => ($accessory_checkout?->accessory?->image) ? Storage::disk('public')->url('accessories/' . e($accessory_checkout->accessory->image)) : null,
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
'created_by' => $accessory_checkout->adminuser ? [
'id' => (int) $accessory_checkout->adminuser->id,
@@ -153,4 +154,16 @@ class LocationsTransformer
return $array;
}
}
}
private function transformAccessory(?Accessory $accessory): ?array
{
if ($accessory) {
return [
'id' => $accessory->id,
'name' => $accessory->name,
];
}
return null;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
class UploadedFilesTransformer
{
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)
{
$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 = [
'id' => (int) $file->id,
'filename' => e($file->filename),
'url' => $file_url,
'created_by' => ($file->adminuser) ? [
'id' => (int) $file->adminuser->id,
'name'=> e($file->adminuser->present()->fullName),
] : null,
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($file->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
];
$permissions_array['available_actions'] = [
'delete' => (Gate::allows('update', $snipeModel) && ($file->deleted_at == '')),
];
$array += $permissions_array;
return $array;
}
}

View File

@@ -16,10 +16,22 @@ class AssetImporter extends ItemImporter
{
parent::__construct($filename);
$this->defaultStatusLabelId = Statuslabel::first()->id;
$this->defaultStatusLabelId = Statuslabel::first()?->id;
if (!is_null(Statuslabel::deployable()->first())) {
$this->defaultStatusLabelId = Statuslabel::deployable()->first()->id;
$this->defaultStatusLabelId = Statuslabel::deployable()->first()?->id;
}
if (is_null($this->defaultStatusLabelId)) {
$defaultLabel = Statuslabel::create([
'name' => 'Default Status',
'deployable' => 0,
'pending' => 1,
'archived' => 0,
'notes' => 'Default status label created by AssetImporter',
]);
$this->defaultStatusLabelId = $defaultLabel->id;
}
}

View File

@@ -28,9 +28,9 @@ class ConsumableImporter extends ItemImporter
{
$consumable = Consumable::where('name', trim($this->item['name']))->first();
if ($consumable) {
if (! $this->updating) {
$this->log('A matching Consumable '.$this->item['name'].' already exists. ');
return;
}
$this->log('Updating Consumable');
@@ -39,12 +39,10 @@ class ConsumableImporter extends ItemImporter
return;
}
$this->log('No matching consumable, creating one');
$consumable = new Consumable();
$consumable->created_by = auth()->id();
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_number'));
$this->item['min_amt'] = trim($this->findCsvMatch($row, "min_amt"));
$consumable->fill($this->sanitizeItemForStoring($consumable));
// This sets an attribute on the Loggable trait for the action log

View File

@@ -24,6 +24,12 @@ class ItemImporter extends Importer
protected function handle($row)
{
/**
* This section adds the most common fields into the $item array so we don't have to manually add them to
* things like accessories, consumables, etc.
*/
// Need to reset this between iterations or we'll have stale data.
$this->item = [];
@@ -73,29 +79,20 @@ class ItemImporter extends Importer
$this->item['notes'] = $this->findCsvMatch($row, 'notes');
$this->item['order_number'] = $this->findCsvMatch($row, 'order_number');
$this->item['purchase_cost'] = $this->findCsvMatch($row, 'purchase_cost');
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
$this->item['min_amt'] = $this->findCsvMatch($row, 'min_amt');
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
$this->item['requestable'] = $this->findCsvMatch($row, 'requestable');
$this->item['created_by'] = auth()->id();
$this->item['serial'] = $this->findCsvMatch($row, 'serial');
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_no'));
$this->item['purchase_date'] = null;
if ($this->findCsvMatch($row, 'purchase_date') != '') {
$this->item['purchase_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'purchase_date')));
}
// $this->item['asset_eol_date'] = null;
// if ($this->findCsvMatch($row, 'asset_eol_date') != '') {
// $csvMatch = $this->findCsvMatch($row, 'asset_eol_date');
// \Log::warning('EOL Date for $csvMatch is '.$csvMatch);
// try {
// $this->item['asset_eol_date'] = CarbonImmutable::parse($csvMatch)->format('Y-m-d');
// } catch (\Exception $e) {
// Log::info($e->getMessage());
// $this->log('Unable to parse date: '.$csvMatch);
// }
// }
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
$this->item['requestable'] = $this->findCsvMatch($row, 'requestable');
$this->item['created_by'] = auth()->id();
$this->item['serial'] = $this->findCsvMatch($row, 'serial');
// NO need to call this method if we're running the user import.
// TODO: Merge these methods.
$this->item['checkout_class'] = $this->findCsvMatch($row, 'checkout_class');
@@ -512,7 +509,6 @@ class ItemImporter extends Importer
if ($supplier->save()) {
$this->log('Supplier '.$item_supplier.' was created');
return $supplier->id;
}
$this->logError($supplier, 'Supplier');

View File

@@ -68,6 +68,7 @@ class LicenseImporter extends ItemImporter
$this->item['order_number'] = trim($this->findCsvMatch($row, 'order_number'));
$this->item['reassignable'] = trim($this->findCsvMatch($row, 'reassignable'));
$this->item['manufacturer'] = $this->createOrFetchManufacturer(trim($this->findCsvMatch($row, 'manufacturer')));
$this->item['min_amt'] = trim($this->findCsvMatch($row, 'min_amt'));
if($this->item['reassignable'] == "")
{

View File

@@ -1,81 +0,0 @@
<?php
namespace App\LegacyEncrypter;
use Illuminate\Contracts\Encryption\DecryptException;
abstract class BaseEncrypter
{
/**
* The encryption key.
*
* @var string
*/
protected $key;
/**
* Create a MAC for the given value.
*
* @param string $iv
* @param string $value
* @return string
*/
protected function hash($iv, $value)
{
return hash_hmac('sha256', $iv.$value, $this->key);
}
/**
* Get the JSON array from the given payload.
*
* @param string $payload
* @return array
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function getJsonPayload($payload)
{
$payload = json_decode(base64_decode($payload), true);
// If the payload is not valid JSON or does not have the proper keys set we will
// assume it is invalid and bail out of the routine since we will not be able
// to decrypt the given value. We'll also check the MAC for this encryption.
if (! $payload || $this->invalidPayload($payload)) {
throw new DecryptException('The payload is invalid.');
}
if (! $this->validMac($payload)) {
throw new DecryptException('The MAC is invalid.');
}
return $payload;
}
/**
* Verify that the encryption payload is valid.
*
* @param array|mixed $data
* @return bool
*/
protected function invalidPayload($data)
{
return ! is_array($data) || ! isset($data['iv']) || ! isset($data['value']) || ! isset($data['mac']);
}
/**
* Determine if the MAC for the given payload is valid.
*
* @param array $payload
* @return bool
*
* @throws \RuntimeException
*/
protected function validMac(array $payload)
{
$bytes = random_bytes(16);
$calcMac = hash_hmac('sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true);
return hash_equals(hash_hmac('sha256', $payload['mac'], $bytes, true), $calcMac);
}
}

View File

@@ -1,214 +0,0 @@
<?php
namespace App\LegacyEncrypter;
use Exception;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;
use Illuminate\Contracts\Encryption\EncryptException;
use RuntimeException;
/**
* @deprecated since version 5.1. Use Illuminate\Encryption\Encrypter.
*/
class McryptEncrypter extends BaseEncrypter implements EncrypterContract
{
/**
* The algorithm used for encryption.
*
* @var string
*/
protected $cipher;
/**
* The block size of the cipher.
*
* @var int
*/
protected $block;
/**
* Create a new encrypter instance.
*
* @param string $key
* @param string $cipher
* @return void
*
* @throws \RuntimeException
*/
public function __construct($key, $cipher = MCRYPT_RIJNDAEL_128)
{
$key = (string) $key;
if (static::supported($key, $cipher)) {
$this->key = $key;
$this->cipher = $cipher;
$this->block = mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
} else {
throw new RuntimeException('The only supported ciphers are MCRYPT_RIJNDAEL_128 and MCRYPT_RIJNDAEL_256.');
}
}
/**
* Determine if the given key and cipher combination is valid.
*
* @param string $key
* @param string $cipher
* @return bool
*/
public static function supported($key, $cipher)
{
return defined('MCRYPT_RIJNDAEL_128') &&
($cipher === MCRYPT_RIJNDAEL_128 || $cipher === MCRYPT_RIJNDAEL_256);
}
/**
* Encrypt the given value.
*
* @param string $value
* @return string
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function encrypt($value, $serialize = true)
{
$iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
$value = base64_encode($this->padAndMcrypt($value, $iv));
// Once we have the encrypted value we will go ahead base64_encode the input
// vector and create the MAC for the encrypted value so we can verify its
// authenticity. Then, we'll JSON encode the data in a "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
$json = json_encode(compact('iv', 'value', 'mac'));
if (! is_string($json)) {
throw new EncryptException('Could not encrypt the data.');
}
return base64_encode($json);
}
/**
* Pad and use mcrypt on the given value and input vector.
*
* @param string $value
* @param string $iv
* @return string
*/
protected function padAndMcrypt($value, $iv)
{
$value = $this->addPadding(serialize($value));
return mcrypt_encrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
}
/**
* Decrypt the given value.
*
* @param string $payload
* @return string
*/
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
// We'll go ahead and remove the PKCS7 padding from the encrypted value before
// we decrypt it. Once we have the de-padded value, we will grab the vector
// and decrypt the data, passing back the unserialized from of the value.
$value = base64_decode($payload['value']);
$iv = base64_decode($payload['iv']);
return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
}
/**
* Run the mcrypt decryption routine for the value.
*
* @param string $value
* @param string $iv
* @return string
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function mcryptDecrypt($value, $iv)
{
try {
return mcrypt_decrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
} catch (Exception $e) {
throw new DecryptException($e->getMessage());
}
}
/**
* Add PKCS7 padding to a given value.
*
* @param string $value
* @return string
*/
protected function addPadding($value)
{
$pad = $this->block - (strlen($value) % $this->block);
return $value.str_repeat(chr($pad), $pad);
}
/**
* Remove the padding from the given value.
*
* @param string $value
* @return string
*/
protected function stripPadding($value)
{
$pad = ord($value[($len = strlen($value)) - 1]);
return $this->paddingIsValid($pad, $value) ? substr($value, 0, $len - $pad) : $value;
}
/**
* Determine if the given padding for a value is valid.
*
* @param string $pad
* @param string $value
* @return bool
*/
protected function paddingIsValid($pad, $value)
{
$beforePad = strlen($value) - $pad;
return substr($value, $beforePad) == str_repeat(substr($value, -1), $pad);
}
/**
* Get the IV size for the cipher.
*
* @return int
*/
protected function getIvSize()
{
return mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
}
/**
* Get the random data source available for the OS.
*
* @return int
*/
protected function getRandomizer()
{
if (defined('MCRYPT_DEV_URANDOM')) {
return MCRYPT_DEV_URANDOM;
}
if (defined('MCRYPT_DEV_RANDOM')) {
return MCRYPT_DEV_RANDOM;
}
mt_srand();
return MCRYPT_RAND;
}
}

View File

@@ -63,11 +63,9 @@ class CheckoutableListener
}
$ccEmails = array_filter($adminCcEmailsArray);
$mailable = $this->getCheckoutMailType($event, $acceptance);
$notifiable = $this->getNotifiables($event);
$notifiable = $this->getNotifiableUsers($event);
if ($event->checkedOutTo->locale) {
$mailable->locale($event->checkedOutTo->locale);
}
// Send email notifications
try {
/**
@@ -75,24 +73,33 @@ class CheckoutableListener
* 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() ||
$this->checkoutableShouldSendEmail($event)) {
Log::info('Sending checkout email, Locale: ' . ($event->checkedOutTo->locale ?? 'default'));
if (!empty($notifiable)) {
Mail::to($notifiable)->cc($ccEmails)->send($mailable);
} elseif (!empty($ccEmails)) {
Mail::cc($ccEmails)->send($mailable);
// Send a checkout email to the admin CC addresses, even if the target has no email
if (!empty($ccEmails)) {
Mail::to($ccEmails)->send($mailable);
Log::info('Checkout Mail sent to CC addresses');
}
Log::info('Checkout Mail sent.');
// 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');
}
}
} catch (ClientException $e) {
Log::debug("Exception caught during checkout email: " . $e->getMessage());
} catch (Exception $e) {
Log::debug("Exception caught during checkout email: " . $e->getMessage());
}
// Send Webhook notification
// Send notification
try {
if ($this->shouldSendWebhookNotification()) {
if ($this->newMicrosoftTeamsWebhookEnabled()) {
@@ -115,7 +122,7 @@ class CheckoutableListener
}
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) .trans('admin/settings/message.webhook.webhook_fail') );
} catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
Log::warning(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event,
@@ -161,10 +168,8 @@ class CheckoutableListener
}
$ccEmails = array_filter($adminCcEmailsArray);
$mailable = $this->getCheckinMailType($event);
$notifiable = $this->getNotifiables($event);
if ($event->checkedOutTo?->locale) {
$mailable->locale($event->checkedOutTo->locale);
}
$notifiable = $this->getNotifiableUsers($event);
// Send email notifications
try {
/**
@@ -172,17 +177,20 @@ class CheckoutableListener
* 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)
*/
if ($event->checkoutable->requireAcceptance() || $event->checkoutable->getEula() ||
$this->checkoutableShouldSendEmail($event)) {
Log::info('Sending checkin email, Locale: ' . ($event->checkedOutTo->locale ?? 'default'));
if (!empty($notifiable)) {
Mail::to($notifiable)->cc($ccEmails)->send($mailable);
} elseif (!empty($ccEmails)){
Mail::cc($ccEmails)->send($mailable);
}
Log::info('Checkin Mail sent.');
}
// Send a checkout email to the admin's CC addresses, even if the target has no email
if (!empty($ccEmails)) {
Mail::to($ccEmails)->send($mailable);
Log::info('Checkin 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('Checkin Mail sent to checkout target');
}
} catch (ClientException $e) {
Log::debug("Exception caught during checkin email: " . $e->getMessage());
} catch (Exception $e) {
@@ -211,7 +219,7 @@ class CheckoutableListener
return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
}
} catch (Exception $e) {
Log::error(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
Log::warning(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event,
@@ -324,17 +332,29 @@ class CheckoutableListener
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
}
private function getNotifiables($event){
if($event->checkedOutTo instanceof Asset){
/**
* This gets the recipient objects based on the type of checkoutable.
* The 'name' property for users is set in the boot method in the User model.
*
* @see \App\Models\User::boot()
* @param $event
* @return mixed
*/
private function getNotifiableUsers($event){
// If it's assigned to an asset, get that asset's assignedTo object
if ($event->checkedOutTo instanceof Asset){
$event->checkedOutTo->load('assignedTo');
return $event->checkedOutTo->assignedto?->email ?? '';
}
else if($event->checkedOutTo instanceof Location) {
return $event->checkedOutTo->manager?->email ?? '';
}
else{
return $event->checkedOutTo?->email ?? '';
return $event->checkedOutTo->assignedto;
// If it's assigned to a location, get that location's manager object
} elseif ($event->checkedOutTo instanceof Location) {
return $event->checkedOutTo->manager;
// Otherwise just return the assigned to object
} else {
return $event->checkedOutTo;
}
}
private function webhookSelected(){
@@ -365,9 +385,25 @@ class CheckoutableListener
private function shouldNotSendAnyNotifications($checkoutable): bool
{
return in_array(get_class($checkoutable), $this->skipNotificationsFor);
if(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
{
return Setting::getSettings() && Setting::getSettings()->webhook_endpoint;

View File

@@ -65,6 +65,7 @@ class LogListener
$logaction->filename = $event->acceptance->stored_eula_file;
$logaction->note = $event->acceptance->note;
$logaction->action_type = 'accepted';
$logaction->action_date = $event->acceptance->accepted_at;
// TODO: log the actual license seat that was checked out
if ($event->acceptance->checkoutable instanceof LicenseSeat) {
@@ -82,6 +83,7 @@ class LogListener
$logaction->accept_signature = $event->acceptance->signature_filename;
$logaction->note = $event->acceptance->note;
$logaction->action_type = 'declined';
$logaction->action_date = $event->acceptance->declined_at;
// TODO: log the actual license seat that was checked out
if ($event->acceptance->checkoutable instanceof LicenseSeat) {

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