mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Merge branch 'develop' into develop
This commit is contained in:
commit
c50ab1af67
|
@ -3018,6 +3018,151 @@
|
||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "koiakoia",
|
||||||
|
"name": "koiakoia",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/60405354?v=4",
|
||||||
|
"profile": "https://github.com/koiakoia",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "mustafa-online",
|
||||||
|
"name": "Mustafa Online",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/5323832?v=4",
|
||||||
|
"profile": "https://github.com/mustafa-online",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "franceslui",
|
||||||
|
"name": "franceslui",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/104601439?v=4",
|
||||||
|
"profile": "https://github.com/franceslui",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Q4kK",
|
||||||
|
"name": "Q4kK",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/125313163?v=4",
|
||||||
|
"profile": "https://github.com/Q4kK",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "squintfox",
|
||||||
|
"name": "squintfox",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/55590532?v=4",
|
||||||
|
"profile": "https://github.com/squintfox",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jeffclay",
|
||||||
|
"name": "Jeff Clay",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1380084?v=4",
|
||||||
|
"profile": "https://github.com/jeffclay",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "PP-JN-RL",
|
||||||
|
"name": "Phil J R",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/52716446?v=4",
|
||||||
|
"profile": "https://github.com/PP-JN-RL",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "chandanchowdhury",
|
||||||
|
"name": "i_virus",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1496725?v=4",
|
||||||
|
"profile": "https://www.corelight.com/",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "gitgrimbo",
|
||||||
|
"name": "Paul Grime",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1020541?v=4",
|
||||||
|
"profile": "https://github.com/gitgrimbo",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "LeePorte",
|
||||||
|
"name": "Lee Porte",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/922815?v=4",
|
||||||
|
"profile": "https://leeporte.co.uk",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "bryanlopezinc",
|
||||||
|
"name": "BRYAN ",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/23613427?v=4",
|
||||||
|
"profile": "https://github.com/bryanlopezinc",
|
||||||
|
"contributions": [
|
||||||
|
"code",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "U-H-T",
|
||||||
|
"name": "U-H-T",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/64061710?v=4",
|
||||||
|
"profile": "https://github.com/U-H-T",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Tyree",
|
||||||
|
"name": "Matt Tyree",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/5395363?v=4",
|
||||||
|
"profile": "https://github.com/Tyree",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "FlorentDotMe",
|
||||||
|
"name": "Florent Bervas",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/292081?v=4",
|
||||||
|
"profile": "http://spoontux.net",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "dbakan",
|
||||||
|
"name": "Daniel Albertsen",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/4498077?v=4",
|
||||||
|
"profile": "https://ditscheri.com",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "r-xyz",
|
||||||
|
"name": "r-xyz",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/100710244?v=4",
|
||||||
|
"profile": "https://github.com/r-xyz",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
166
.env.dev.docker
Normal file
166
.env.dev.docker
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DB SETUP
|
||||||
|
# --------------------------------------------
|
||||||
|
MYSQL_DATABASE=snipeit
|
||||||
|
MYSQL_USER=snipeit
|
||||||
|
MYSQL_PASSWORD=changeme1234
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme1234
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: BASIC APP SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
APP_ENV=develop
|
||||||
|
APP_DEBUG=false
|
||||||
|
# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here
|
||||||
|
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
APP_TIMEZONE='UTC'
|
||||||
|
APP_LOCALE=en
|
||||||
|
MAX_RESULTS=500
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: UPLOADED FILE STORAGE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
PRIVATE_FILESYSTEM_DISK=local
|
||||||
|
PUBLIC_FILESYSTEM_DISK=local_public
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DATABASE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=mariadb
|
||||||
|
DB_DATABASE=snipeit
|
||||||
|
DB_USERNAME=snipeit
|
||||||
|
DB_PASSWORD=changeme1234
|
||||||
|
DB_PREFIX=null
|
||||||
|
DB_DUMP_PATH='/usr/bin'
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
DB_COLLATION=utf8mb4_unicode_ci
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SSL DATABASE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
DB_SSL=false
|
||||||
|
DB_SSL_IS_PAAS=false
|
||||||
|
DB_SSL_KEY_PATH=null
|
||||||
|
DB_SSL_CERT_PATH=null
|
||||||
|
DB_SSL_CA_PATH=null
|
||||||
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MAIL_DRIVER=smtp
|
||||||
|
MAIL_HOST=mailhog
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDR=you@example.com
|
||||||
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: IMAGE LIBRARY
|
||||||
|
# This should be gd or imagick
|
||||||
|
# --------------------------------------------
|
||||||
|
IMAGE_LIB=gd
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: BACKUP SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
||||||
|
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||||
|
BACKUP_ENV=true
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SESSION SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
SESSION_LIFETIME=12000
|
||||||
|
EXPIRE_ON_CLOSE=false
|
||||||
|
ENCRYPT=false
|
||||||
|
COOKIE_NAME=snipeit_session
|
||||||
|
COOKIE_DOMAIN=null
|
||||||
|
SECURE_COOKIES=false
|
||||||
|
API_TOKEN_EXPIRATION_YEARS=40
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
||||||
|
ALLOW_IFRAMING=false
|
||||||
|
REFERRER_POLICY=same-origin
|
||||||
|
ENABLE_CSP=false
|
||||||
|
CORS_ALLOWED_ORIGINS=null
|
||||||
|
ENABLE_HSTS=false
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: CACHE SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
QUEUE_DRIVER=sync
|
||||||
|
CACHE_PREFIX=snipeit
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: REDIS SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: MEMCACHED SETTINGS
|
||||||
|
# --------------------------------------------
|
||||||
|
MEMCACHED_HOST=null
|
||||||
|
MEMCACHED_PORT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: PUBLIC S3 Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
PUBLIC_AWS_SECRET_ACCESS_KEY=null
|
||||||
|
PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||||
|
PUBLIC_AWS_DEFAULT_REGION=null
|
||||||
|
PUBLIC_AWS_BUCKET=null
|
||||||
|
PUBLIC_AWS_URL=null
|
||||||
|
PUBLIC_AWS_BUCKET_ROOT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: PRIVATE S3 Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
PRIVATE_AWS_ACCESS_KEY_ID=null
|
||||||
|
PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||||
|
PRIVATE_AWS_DEFAULT_REGION=null
|
||||||
|
PRIVATE_AWS_BUCKET=null
|
||||||
|
PRIVATE_AWS_URL=null
|
||||||
|
PRIVATE_AWS_BUCKET_ROOT=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: AWS Settings
|
||||||
|
# --------------------------------------------
|
||||||
|
AWS_ACCESS_KEY_ID=null
|
||||||
|
AWS_SECRET_ACCESS_KEY=null
|
||||||
|
AWS_DEFAULT_REGION=null
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: LOGIN THROTTLING
|
||||||
|
# --------------------------------------------
|
||||||
|
LOGIN_MAX_ATTEMPTS=5
|
||||||
|
LOGIN_LOCKOUT_DURATION=60
|
||||||
|
RESET_PASSWORD_LINK_EXPIRES=900
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# OPTIONAL: MISC
|
||||||
|
# --------------------------------------------
|
||||||
|
LOG_CHANNEL=stderr
|
||||||
|
LOG_MAX_DAYS=10
|
||||||
|
APP_LOCKED=false
|
||||||
|
APP_CIPHER=AES-256-CBC
|
||||||
|
APP_FORCE_TLS=false
|
||||||
|
GOOGLE_MAPS_API=
|
||||||
|
LDAP_MEM_LIM=500M
|
||||||
|
LDAP_TIME_LIM=600
|
35
.env.docker
35
.env.docker
|
@ -1,18 +1,18 @@
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: DB SETUP
|
# REQUIRED: DOCKER SPECIFIC SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MYSQL_DATABASE=snipeit
|
APP_VERSION=v6.4.1
|
||||||
MYSQL_USER=snipeit
|
APP_PORT=8000
|
||||||
MYSQL_PASSWORD=changeme1234
|
|
||||||
MYSQL_ROOT_PASSWORD=changeme1234
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: BASIC APP SETTINGS
|
# REQUIRED: BASIC APP SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
APP_ENV=develop
|
APP_ENV=production
|
||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here
|
# Please regenerate the APP_KEY value by calling `docker compose run --rm snipeit php artisan key:generate --show`. Copy paste the value here
|
||||||
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||||
APP_URL=http://localhost:8000
|
APP_URL=http://localhost:8000
|
||||||
|
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
||||||
APP_TIMEZONE='UTC'
|
APP_TIMEZONE='UTC'
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
MAX_RESULTS=500
|
MAX_RESULTS=500
|
||||||
|
@ -27,10 +27,12 @@ PUBLIC_FILESYSTEM_DISK=local_public
|
||||||
# REQUIRED: DATABASE SETTINGS
|
# REQUIRED: DATABASE SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=mariadb
|
DB_HOST=db
|
||||||
|
DB_PORT='3306'
|
||||||
DB_DATABASE=snipeit
|
DB_DATABASE=snipeit
|
||||||
DB_USERNAME=snipeit
|
DB_USERNAME=snipeit
|
||||||
DB_PASSWORD=changeme1234
|
DB_PASSWORD=changeme1234
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme1234
|
||||||
DB_PREFIX=null
|
DB_PREFIX=null
|
||||||
DB_DUMP_PATH='/usr/bin'
|
DB_DUMP_PATH='/usr/bin'
|
||||||
DB_CHARSET=utf8mb4
|
DB_CHARSET=utf8mb4
|
||||||
|
@ -45,29 +47,35 @@ DB_SSL_KEY_PATH=null
|
||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=mailhog
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=1025
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_TLS_VERIFY_PEER=true
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME='Snipe-IT'
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
MAIL_REPLYTO_ADDR=you@example.com
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
MAIL_REPLYTO_NAME='Snipe-IT'
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
MAIL_AUTO_EMBED_METHOD='attachment'
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# REQUIRED: DATA PROTECTION
|
||||||
|
# --------------------------------------------
|
||||||
|
ALLOW_BACKUP_DELETE=false
|
||||||
|
ALLOW_DATA_PURGE=false
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: IMAGE LIBRARY
|
# REQUIRED: IMAGE LIBRARY
|
||||||
# This should be gd or imagick
|
# This should be gd or imagick
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
IMAGE_LIB=gd
|
IMAGE_LIB=gd
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: BACKUP SETTINGS
|
# OPTIONAL: BACKUP SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
@ -75,7 +83,6 @@ MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
||||||
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||||
BACKUP_ENV=true
|
BACKUP_ENV=true
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: SESSION SETTINGS
|
# OPTIONAL: SESSION SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
@ -90,7 +97,7 @@ API_TOKEN_EXPIRATION_YEARS=40
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: SECURITY HEADER SETTINGS
|
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1,172.0.0.0/8
|
||||||
ALLOW_IFRAMING=false
|
ALLOW_IFRAMING=false
|
||||||
REFERRER_POLICY=same-origin
|
REFERRER_POLICY=same-origin
|
||||||
ENABLE_CSP=false
|
ENABLE_CSP=false
|
||||||
|
@ -108,7 +115,7 @@ CACHE_PREFIX=snipeit
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: REDIS SETTINGS
|
# OPTIONAL: REDIS SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=null
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,12 @@ DB_SSL_KEY_PATH=null
|
||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER="log"
|
MAIL_MAILER="log"
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|
13
.env.example
13
.env.example
|
@ -42,21 +42,26 @@ DB_SSL_KEY_PATH=null
|
||||||
DB_SSL_CERT_PATH=null
|
DB_SSL_CERT_PATH=null
|
||||||
DB_SSL_CA_PATH=null
|
DB_SSL_CA_PATH=null
|
||||||
DB_SSL_CIPHER=null
|
DB_SSL_CIPHER=null
|
||||||
|
DB_SSL_VERIFY_SERVER=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
|
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
|
||||||
MAIL_PORT=587
|
MAIL_PORT=587
|
||||||
MAIL_USERNAME=YOURUSERNAME
|
MAIL_USERNAME=YOURUSERNAME
|
||||||
MAIL_PASSWORD=YOURPASSWORD
|
MAIL_PASSWORD=YOURPASSWORD
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME='Snipe-IT'
|
MAIL_FROM_NAME='Snipe-IT'
|
||||||
MAIL_REPLYTO_ADDR=you@example.com
|
MAIL_REPLYTO_ADDR=you@example.com
|
||||||
MAIL_REPLYTO_NAME='Snipe-IT'
|
MAIL_REPLYTO_NAME='Snipe-IT'
|
||||||
MAIL_AUTO_EMBED_METHOD='attachment'
|
MAIL_AUTO_EMBED_METHOD='attachment'
|
||||||
|
MAIL_TLS_VERIFY_PEER=true
|
||||||
|
|
||||||
|
# MAIL_ENCRYPTION is no longer supported. SymfonyMailer will use tls if it's
|
||||||
|
# advertised, and won't if it's not. If you want to use your mail server's IP but it's failing
|
||||||
|
# because of certificate errors, set MAIL_TLS_VERIFY_PEER-true
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: IMAGE LIBRARY
|
# REQUIRED: IMAGE LIBRARY
|
||||||
|
@ -95,6 +100,7 @@ APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
|
||||||
ALLOW_IFRAMING=false
|
ALLOW_IFRAMING=false
|
||||||
REFERRER_POLICY=same-origin
|
REFERRER_POLICY=same-origin
|
||||||
ENABLE_CSP=false
|
ENABLE_CSP=false
|
||||||
|
ADDITIONAL_CSP_URLS=null
|
||||||
CORS_ALLOWED_ORIGINS=null
|
CORS_ALLOWED_ORIGINS=null
|
||||||
ENABLE_HSTS=false
|
ENABLE_HSTS=false
|
||||||
|
|
||||||
|
@ -177,6 +183,7 @@ REPORT_TIME_LIMIT=12000
|
||||||
REQUIRE_SAML=false
|
REQUIRE_SAML=false
|
||||||
API_THROTTLE_PER_MINUTE=120
|
API_THROTTLE_PER_MINUTE=120
|
||||||
CSV_ESCAPE_FORMULAS=true
|
CSV_ESCAPE_FORMULAS=true
|
||||||
|
LIVEWIRE_URL_PREFIX=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: HASHING
|
# OPTIONAL: HASHING
|
||||||
|
@ -191,4 +198,4 @@ ARGON_TIME=2
|
||||||
# OPTIONAL: SCIM
|
# OPTIONAL: SCIM
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
SCIM_TRACE=false
|
SCIM_TRACE=false
|
||||||
SCIM_STANDARDS_COMPLIANCE=false
|
SCIM_STANDARDS_COMPLIANCE=false
|
||||||
|
|
|
@ -22,7 +22,7 @@ DB_PASSWORD=null
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|
|
@ -18,6 +18,6 @@ APP_KEY=base64:tu9NRh/a6+dCXBDGvg0Gv/0TcABnFsbT4AKxrr8mwQo=
|
||||||
LOGIN_MAX_ATTEMPTS=1000000
|
LOGIN_MAX_ATTEMPTS=1000000
|
||||||
LOGIN_LOCKOUT_DURATION=100000000
|
LOGIN_LOCKOUT_DURATION=100000000
|
||||||
|
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME=Snipe-IT
|
MAIL_FROM_NAME=Snipe-IT
|
||||||
|
|
|
@ -15,6 +15,6 @@ APP_KEY=base64:tu9NRh/a6+dCXBDGvg0Gv/0TcABnFsbT4AKxrr8mwQo=
|
||||||
LOGIN_MAX_ATTEMPTS=1000000
|
LOGIN_MAX_ATTEMPTS=1000000
|
||||||
LOGIN_LOCKOUT_DURATION=100000000
|
LOGIN_LOCKOUT_DURATION=100000000
|
||||||
|
|
||||||
MAIL_DRIVER=log
|
MAIL_MAILER=log
|
||||||
MAIL_FROM_ADDR=you@example.com
|
MAIL_FROM_ADDR=you@example.com
|
||||||
MAIL_FROM_NAME=Snipe-IT
|
MAIL_FROM_NAME=Snipe-IT
|
||||||
|
|
2
.github/workflows/codacy-analysis.yml
vendored
2
.github/workflows/codacy-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
|
|
||||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||||
- name: Run Codacy Analysis CLI
|
- name: Run Codacy Analysis CLI
|
||||||
uses: codacy/codacy-analysis-cli-action@v4.4.0
|
uses: codacy/codacy-analysis-cli-action@v4.4.5
|
||||||
with:
|
with:
|
||||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||||
# You can also omit the token and run the tools that support default configurations
|
# You can also omit the token and run the tools that support default configurations
|
||||||
|
|
2
.github/workflows/crowdin-upload.yml
vendored
2
.github/workflows/crowdin-upload.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Crowdin push
|
- name: Crowdin push
|
||||||
uses: crowdin/github-action@v1
|
uses: crowdin/github-action@v2
|
||||||
with:
|
with:
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
|
|
2
.github/workflows/docker-alpine.yml
vendored
2
.github/workflows/docker-alpine.yml
vendored
|
@ -73,7 +73,7 @@ jobs:
|
||||||
# https://github.com/docker/build-push-action
|
# https://github.com/docker/build-push-action
|
||||||
- name: Build and push 'snipe-it' image
|
- name: Build and push 'snipe-it' image
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile.alpine
|
file: ./Dockerfile.alpine
|
||||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -73,7 +73,7 @@ jobs:
|
||||||
# https://github.com/docker/build-push-action
|
# https://github.com/docker/build-push-action
|
||||||
- name: Build and push 'snipe-it' image
|
- name: Build and push 'snipe-it' image
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|
22
.github/workflows/tests-mysql.yml
vendored
22
.github/workflows/tests-mysql.yml
vendored
|
@ -25,9 +25,9 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php-version:
|
php-version:
|
||||||
- "7.4"
|
- "8.1"
|
||||||
- "8.0"
|
- "8.2"
|
||||||
- "8.1.1"
|
- "8.3"
|
||||||
|
|
||||||
name: PHP ${{ matrix.php-version }}
|
name: PHP ${{ matrix.php-version }}
|
||||||
|
|
||||||
|
@ -58,11 +58,17 @@ jobs:
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
- name: Generate key
|
- name: Setup Laravel
|
||||||
run: php artisan key:generate
|
env:
|
||||||
|
DB_CONNECTION: mysql
|
||||||
- name: Directory Permissions
|
DB_DATABASE: snipeit
|
||||||
run: chmod -R 777 storage bootstrap/cache
|
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||||
|
DB_USERNAME: root
|
||||||
|
run: |
|
||||||
|
php artisan key:generate
|
||||||
|
php artisan migrate --force
|
||||||
|
php artisan passport:install
|
||||||
|
chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||||
env:
|
env:
|
||||||
|
|
77
.github/workflows/tests-postgres.yml
vendored
Normal file
77
.github/workflows/tests-postgres.yml
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
name: Tests in Postgres
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: postgres
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: snipeit
|
||||||
|
POSTGRES_USER: snipeit
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php-version:
|
||||||
|
- "8.1"
|
||||||
|
- "8.2"
|
||||||
|
- "8.3"
|
||||||
|
|
||||||
|
name: PHP ${{ matrix.php-version }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "${{ matrix.php-version }}"
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get Composer Cache Directory
|
||||||
|
id: composer-cache
|
||||||
|
run: |
|
||||||
|
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-composer-
|
||||||
|
|
||||||
|
- name: Copy .env
|
||||||
|
run: |
|
||||||
|
cp -v .env.testing.example .env
|
||||||
|
cp -v .env.testing.example .env.testing
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
|
- name: Setup Laravel
|
||||||
|
env:
|
||||||
|
DB_CONNECTION: pgsql
|
||||||
|
DB_DATABASE: snipeit
|
||||||
|
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||||
|
DB_USERNAME: snipeit
|
||||||
|
DB_PASSWORD: password
|
||||||
|
run: |
|
||||||
|
php artisan key:generate
|
||||||
|
php artisan migrate --force
|
||||||
|
php artisan passport:install
|
||||||
|
chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
|
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||||
|
env:
|
||||||
|
DB_CONNECTION: pgsql
|
||||||
|
DB_DATABASE: snipeit
|
||||||
|
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||||
|
DB_USERNAME: snipeit
|
||||||
|
DB_PASSWORD: password
|
||||||
|
run: php artisan test --parallel
|
3
.github/workflows/tests-sqlite.yml
vendored
3
.github/workflows/tests-sqlite.yml
vendored
|
@ -49,6 +49,9 @@ jobs:
|
||||||
- name: Generate key
|
- name: Generate key
|
||||||
run: php artisan key:generate
|
run: php artisan key:generate
|
||||||
|
|
||||||
|
- name: Setup Passport
|
||||||
|
run: php artisan passport:keys
|
||||||
|
|
||||||
- name: Directory Permissions
|
- name: Directory Permissions
|
||||||
run: chmod -R 777 storage bootstrap/cache
|
run: chmod -R 777 storage bootstrap/cache
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
|
"DOC2": "In other words, what you see locally are the requirements for your _current_ install",
|
||||||
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
|
"DOC3": "Please don't rely on these versions for planning upgrades unless you've fetched the most recent version",
|
||||||
"DOC4": "You should really just ignore it and run upgrade.php. Really",
|
"DOC4": "You should really just ignore it and run upgrade.php. Really",
|
||||||
"php_min_version": "7.4.0",
|
"php_min_version": "8.1.0",
|
||||||
"php_max_major_minor": "8.1",
|
"php_max_major_minor": "8.3",
|
||||||
"php_max_wontwork": "8.2.0",
|
"php_max_wontwork": "8.4.0",
|
||||||
"current_snipeit_version": "6.3"
|
"current_snipeit_version": "7.0"
|
||||||
}
|
}
|
||||||
|
|
489
CONTRIBUTORS.md
489
CONTRIBUTORS.md
|
@ -1,444 +1,57 @@
|
||||||
Thanks goes to all of these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)) who have helped Snipe-IT get this far:
|
Thanks goes to all of these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)) who have helped Snipe-IT get this far:
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
<!-- prettier-ignore-start -->
|
| [<img src="https://avatars3.githubusercontent.com/u/197404?v=3" width="110px;"/><br /><sub>snipe</sub>](http://www.snipe.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=snipe "Code") [🚇](#infra-snipe "Infrastructure (Hosting, Build-Tools, etc)") [📖](https://github.com/snipe/snipe-it/commits?author=snipe "Documentation") [⚠️](https://github.com/snipe/snipe-it/commits?author=snipe "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Asnipe "Bug reports") [🎨](#design-snipe "Design") [👀](#review-snipe "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/36335?v=3" width="110px;"/><br /><sub>Brady Wetherington</sub>](http://www.uberbrady.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=uberbrady "Code") [📖](https://github.com/snipe/snipe-it/commits?author=uberbrady "Documentation") [🚇](#infra-uberbrady "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-uberbrady "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/3803132?v=3" width="110px;"/><br /><sub>Daniel Meltzer</sub>](https://github.com/dmeltzer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Tests") [📖](https://github.com/snipe/snipe-it/commits?author=dmeltzer "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/1609106?v=3" width="110px;"/><br /><sub>Michael T</sub>](http://www.tuckertechonline.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mtucker6784 "Code") | [<img src="https://avatars2.githubusercontent.com/u/3274937?v=3" width="110px;"/><br /><sub>madd15</sub>](https://github.com/madd15)<br />[📖](https://github.com/snipe/snipe-it/commits?author=madd15 "Documentation") [💬](#question-madd15 "Answering Questions") | [<img src="https://avatars2.githubusercontent.com/u/894126?v=3" width="110px;"/><br /><sub>Vincent Sposato</sub>](https://github.com/vsposato)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vsposato "Code") | [<img src="https://avatars0.githubusercontent.com/u/1639757?v=3" width="110px;"/><br /><sub>Andrea Bergamasco</sub>](https://github.com/vjandrea)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vjandrea "Code") |
|
||||||
<!-- markdownlint-disable -->
|
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||||
<table>
|
| [<img src="https://avatars0.githubusercontent.com/u/10640152?v=3" width="110px;"/><br /><sub>Karol</sub>](https://github.com/kpawelski)<br />[🌍](#translation-kpawelski "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=kpawelski "Code") | [<img src="https://avatars3.githubusercontent.com/u/600106?v=3" width="110px;"/><br /><sub>morph027</sub>](http://blog.morph027.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=morph027 "Code") | [<img src="https://avatars3.githubusercontent.com/u/22935755?v=3" width="110px;"/><br /><sub>fvleminckx</sub>](https://github.com/fvleminckx)<br />[🚇](#infra-fvleminckx "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars2.githubusercontent.com/u/15633547?v=3" width="110px;"/><br /><sub>itsupportcmsukorg</sub>](https://github.com/itsupportcmsukorg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=itsupportcmsukorg "Code") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aitsupportcmsukorg "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/12373799?v=3" width="110px;"/><br /><sub>Frank</sub>](https://override.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=base-zero "Code") | [<img src="https://avatars0.githubusercontent.com/u/10137?v=3" width="110px;"/><br /><sub>Deleted user</sub>](https://github.com/ghost)<br />[🌍](#translation-ghost "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=ghost "Code") | [<img src="https://avatars1.githubusercontent.com/u/10802313?v=3" width="110px;"/><br /><sub>tiagom62</sub>](https://github.com/tiagom62)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tiagom62 "Code") [🚇](#infra-tiagom62 "Infrastructure (Hosting, Build-Tools, etc)") |
|
||||||
<tbody>
|
| [<img src="https://avatars3.githubusercontent.com/u/2389047?v=3" width="110px;"/><br /><sub>Ryan Stafford</sub>](https://github.com/rystaf)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rystaf "Code") | [<img src="https://avatars2.githubusercontent.com/u/10345935?v=3" width="110px;"/><br /><sub>Eammon Hanlon</sub>](https://github.com/ehanlon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ehanlon "Code") | [<img src="https://avatars0.githubusercontent.com/u/441924?v=3" width="110px;"/><br /><sub>zjean</sub>](https://github.com/zjean)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zjean "Code") | [<img src="https://avatars0.githubusercontent.com/u/12660103?v=3" width="110px;"/><br /><sub>Matthias Frei</sub>](http://www.frei.media)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FREImedia "Code") | [<img src="https://avatars0.githubusercontent.com/u/3767518?v=3" width="110px;"/><br /><sub>opsydev</sub>](https://github.com/opsydev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=opsydev "Code") | [<img src="https://avatars1.githubusercontent.com/u/82290?v=3" width="110px;"/><br /><sub>Daniel Dreier</sub>](http://www.ddreier.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ddreier "Code") | [<img src="https://avatars0.githubusercontent.com/u/23448?v=3" width="110px;"/><br /><sub>Nikolai Prokoschenko</sub>](http://rassie.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rassie "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars0.githubusercontent.com/u/13452757?v=3" width="110px;"/><br /><sub>Drew</sub>](https://github.com/YetAnotherCodeMonkey)<br />[💻](https://github.com/snipe/snipe-it/commits?author=YetAnotherCodeMonkey "Code") | [<img src="https://avatars0.githubusercontent.com/u/1342320?v=3" width="110px;"/><br /><sub>Walter</sub>](https://github.com/merid14)<br />[💻](https://github.com/snipe/snipe-it/commits?author=merid14 "Code") | [<img src="https://avatars3.githubusercontent.com/u/11254614?v=3" width="110px;"/><br /><sub>Petr Baloun</sub>](https://github.com/balous)<br />[💻](https://github.com/snipe/snipe-it/commits?author=balous "Code") | [<img src="https://avatars0.githubusercontent.com/u/6117660?v=3" width="110px;"/><br /><sub>reidblomquist</sub>](https://github.com/reidblomquist)<br />[📖](https://github.com/snipe/snipe-it/commits?author=reidblomquist "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/539914?v=3" width="110px;"/><br /><sub>Mathieu Kooiman</sub>](https://github.com/mathieuk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mathieuk "Code") | [<img src="https://avatars3.githubusercontent.com/u/6606421?v=3" width="110px;"/><br /><sub>csayre</sub>](https://github.com/csayre)<br />[📖](https://github.com/snipe/snipe-it/commits?author=csayre "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/768488?v=3" width="110px;"/><br /><sub>Adam Dunson</sub>](https://github.com/adamdunson)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamdunson "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.snipe.net"><img src="https://avatars3.githubusercontent.com/u/197404?v=3?s=110" width="110px;" alt="snipe"/><br /><sub><b>snipe</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Code">💻</a> <a href="#infra-snipe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Documentation">📖</a> <a href="https://github.com/snipe/snipe-it/commits?author=snipe" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3Asnipe" title="Bug reports">🐛</a> <a href="#design-snipe" title="Design">🎨</a> <a href="https://github.com/snipe/snipe-it/pulls?q=is%3Apr+reviewed-by%3Asnipe" title="Reviewed Pull Requests">👀</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/5547470?v=3" width="110px;"/><br /><sub>Hereward</sub>](https://github.com/thehereward)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thehereward "Code") | [<img src="https://avatars0.githubusercontent.com/u/5802977?v=3" width="110px;"/><br /><sub>swoopdk</sub>](https://github.com/swoopdk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=swoopdk "Code") | [<img src="https://avatars1.githubusercontent.com/u/3470403?v=3" width="110px;"/><br /><sub>Abdullah Alansari</sub>](https://linkedin.com/in/ahimta)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Ahimta "Code") | [<img src="https://avatars0.githubusercontent.com/u/796443?v=3" width="110px;"/><br /><sub>Micael Rodrigues</sub>](https://github.com/MicaelRodrigues)<br />[💻](https://github.com/snipe/snipe-it/commits?author=MicaelRodrigues "Code") | [<img src="https://avatars0.githubusercontent.com/u/614564?v=3" width="110px;"/><br /><sub>Patrick Gallagher</sub>](http://macadmincorner.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=patgmac "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/7165922?v=3" width="110px;"/><br /><sub>Miliamber</sub>](https://github.com/Miliamber)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Miliamber "Code") | [<img src="https://avatars3.githubusercontent.com/u/861766?v=3" width="110px;"/><br /><sub>hawk554</sub>](https://github.com/hawk554)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hawk554 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.uberbrady.com"><img src="https://avatars0.githubusercontent.com/u/36335?v=3?s=110" width="110px;" alt="Brady Wetherington"/><br /><sub><b>Brady Wetherington</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=uberbrady" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=uberbrady" title="Documentation">📖</a> <a href="#infra-uberbrady" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/snipe/snipe-it/pulls?q=is%3Apr+reviewed-by%3Auberbrady" title="Reviewed Pull Requests">👀</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/1695622?v=3" width="110px;"/><br /><sub>Justin Kerr</sub>](http://jbirdkerr.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jbirdkerr "Code") | [<img src="https://avatars3.githubusercontent.com/u/11426176?v=3" width="110px;"/><br /><sub>Ira W. Snyder</sub>](http://www.irasnyder.com/devel/)<br />[📖](https://github.com/snipe/snipe-it/commits?author=irasnyd "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/2475759?v=3" width="110px;"/><br /><sub>Aladin Alaily</sub>](https://github.com/aalaily)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aalaily "Code") | [<img src="https://avatars0.githubusercontent.com/u/10247644?v=3" width="110px;"/><br /><sub>Chase Hansen</sub>](https://github.com/kobie-chasehansen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kobie-chasehansen "Code") [💬](#question-kobie-chasehansen "Answering Questions") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3Akobie-chasehansen "Bug reports") | [<img src="https://avatars2.githubusercontent.com/u/13545400?v=3" width="110px;"/><br /><sub>IDM Helpdesk</sub>](https://github.com/IDM-Helpdesk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=IDM-Helpdesk "Code") | [<img src="https://avatars2.githubusercontent.com/u/614439?v=3" width="110px;"/><br /><sub>Kai</sub>](http://balticer.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=balticer "Code") | [<img src="https://avatars1.githubusercontent.com/u/8762511?v=3" width="110px;"/><br /><sub>Michael Daniels</sub>](http://www.michaeldaniels.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mdaniels5757 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dmeltzer"><img src="https://avatars0.githubusercontent.com/u/3803132?v=3?s=110" width="110px;" alt="Daniel Meltzer"/><br /><sub><b>Daniel Meltzer</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Tests">⚠️</a> <a href="https://github.com/snipe/snipe-it/commits?author=dmeltzer" title="Documentation">📖</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/1532660?v=3" width="110px;"/><br /><sub>Tom Castleman</sub>](http://tomcastleman.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tomcastleman "Code") | [<img src="https://avatars3.githubusercontent.com/u/10723243?v=3" width="110px;"/><br /><sub>Daniel Nemanic</sub>](https://github.com/DanielNemanic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DanielNemanic "Code") | [<img src="https://avatars0.githubusercontent.com/u/150648?v=3" width="110px;"/><br /><sub>SouthWolf</sub>](https://github.com/southwolf)<br />[💻](https://github.com/snipe/snipe-it/commits?author=southwolf "Code") | [<img src="https://avatars2.githubusercontent.com/u/131616?v=3" width="110px;"/><br /><sub>Ivar Nesje</sub>](https://github.com/ivarne)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ivarne "Code") | [<img src="https://avatars1.githubusercontent.com/u/62333?v=3" width="110px;"/><br /><sub>Jérémy Benoist</sub>](http://www.j0k3r.net)<br />[📖](https://github.com/snipe/snipe-it/commits?author=j0k3r "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/724344?v=3" width="110px;"/><br /><sub>Chris Leathley</sub>](https://github.com/cleathley)<br />[🚇](#infra-cleathley "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars0.githubusercontent.com/u/972498?v=3" width="110px;"/><br /><sub>splaer</sub>](https://github.com/splaer)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Asplaer "Bug reports") [💻](https://github.com/snipe/snipe-it/commits?author=splaer "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.tuckertechonline.com"><img src="https://avatars0.githubusercontent.com/u/1609106?v=3?s=110" width="110px;" alt="Michael T"/><br /><sub><b>Michael T</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mtucker6784" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/967362?v=3" width="110px;"/><br /><sub>Joe Ferguson</sub>](http://www.joeferguson.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=svpernova09 "Code") | [<img src="https://avatars3.githubusercontent.com/u/6108682?v=3" width="110px;"/><br /><sub>diwanicki</sub>](https://github.com/diwanicki)<br />[💻](https://github.com/snipe/snipe-it/commits?author=diwanicki "Code") [📖](https://github.com/snipe/snipe-it/commits?author=diwanicki "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/2527115?v=3" width="110px;"/><br /><sub>Lee Thoong Ching</sub>](https://github.com/pakkua80)<br />[📖](https://github.com/snipe/snipe-it/commits?author=pakkua80 "Documentation") [💻](https://github.com/snipe/snipe-it/commits?author=pakkua80 "Code") | [<img src="https://avatars1.githubusercontent.com/u/461491?v=3" width="110px;"/><br /><sub>Marek Šuppa</sub>](http://shu.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrshu "Code") | [<img src="https://avatars1.githubusercontent.com/u/8693762?v=3" width="110px;"/><br /><sub>Juan J. Martinez</sub>](https://github.com/mizar1616)<br />[🌍](#translation-mizar1616 "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1458388?v=3" width="110px;"/><br /><sub>R Ryan Dial</sub>](https://github.com/rrdial)<br />[🌍](#translation-rrdial "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2871745?v=3" width="110px;"/><br /><sub>Andrej Manduch</sub>](https://github.com/burlito)<br />[📖](https://github.com/snipe/snipe-it/commits?author=burlito "Documentation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/madd15"><img src="https://avatars2.githubusercontent.com/u/3274937?v=3?s=110" width="110px;" alt="madd15"/><br /><sub><b>madd15</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=madd15" title="Documentation">📖</a> <a href="#question-madd15" title="Answering Questions">💬</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/8341172?v=3" width="110px;"/><br /><sub>Jay Richards</sub>](http://www.cordeos.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=technogenus "Code") | [<img src="https://avatars2.githubusercontent.com/u/7295127?v=3" width="110px;"/><br /><sub>Alexander Innes</sub>](https://necurity.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leostat "Code") | [<img src="https://avatars2.githubusercontent.com/u/334485?v=3" width="110px;"/><br /><sub>Danny Garcia</sub>](https://buzzedword.codes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=buzzedword "Code") | [<img src="https://avatars2.githubusercontent.com/u/366855?v=3" width="110px;"/><br /><sub>archpoint</sub>](https://github.com/archpoint)<br />[💻](https://github.com/snipe/snipe-it/commits?author=archpoint "Code") | [<img src="https://avatars1.githubusercontent.com/u/67991?v=3" width="110px;"/><br /><sub>Jake McGraw</sub>](http://www.jakemcgraw.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jakemcgraw "Code") | [<img src="https://avatars1.githubusercontent.com/u/1714374?v=3" width="110px;"/><br /><sub>FleischKarussel</sub>](https://github.com/FleischKarussel)<br />[📖](https://github.com/snipe/snipe-it/commits?author=FleischKarussel "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/319644?v=3" width="110px;"/><br /><sub>Dylan Yi</sub>](https://github.com/feeva)<br />[💻](https://github.com/snipe/snipe-it/commits?author=feeva "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vsposato"><img src="https://avatars2.githubusercontent.com/u/894126?v=3?s=110" width="110px;" alt="Vincent Sposato"/><br /><sub><b>Vincent Sposato</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vsposato" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/857740?v=3" width="110px;"/><br /><sub>Gil Rutkowski</sub>](http://FlashingCursor.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [<img src="https://avatars3.githubusercontent.com/u/129360?v=3" width="110px;"/><br /><sub>Desmond Morris</sub>](http://www.desmondmorris.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [<img src="https://avatars2.githubusercontent.com/u/52936?v=3" width="110px;"/><br /><sub>Nick Peelman</sub>](http://peelman.us)<br />[💻](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [<img src="https://avatars0.githubusercontent.com/u/53161?v=3" width="110px;"/><br /><sub>Abraham Vegh</sub>](https://abrahamvegh.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [<img src="https://avatars0.githubusercontent.com/u/2818680?v=3" width="110px;"/><br /><sub>Mohamed Rashid</sub>](https://github.com/rashivkp)<br />[📖](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1509456?v=3" width="110px;"/><br /><sub>Kasey</sub>](http://hinchk.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [<img src="https://avatars2.githubusercontent.com/u/10522541?v=3" width="110px;"/><br /><sub>Brett</sub>](https://github.com/BrettFagerlund)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vjandrea"><img src="https://avatars0.githubusercontent.com/u/1639757?v=3?s=110" width="110px;" alt="Andrea Bergamasco"/><br /><sub><b>Andrea Bergamasco</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=vjandrea" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/16108587?v=3" width="110px;"/><br /><sub>Jason Spriggs</sub>](http://jasonspriggs.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [<img src="https://avatars2.githubusercontent.com/u/1134568?v=3" width="110px;"/><br /><sub>Nate Felton</sub>](http://n8felton.wordpress.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [<img src="https://avatars2.githubusercontent.com/u/14036694?v=3" width="110px;"/><br /><sub>Manasses Ferreira</sub>](http://homepages.dcc.ufmg.br/~manassesferreira)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [<img src="https://avatars0.githubusercontent.com/u/15913949?v=3" width="110px;"/><br /><sub>Steve</sub>](https://github.com/steveelwood)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [<img src="https://avatars1.githubusercontent.com/u/3361683?v=3" width="110px;"/><br /><sub>matc</sub>](http://twitter.com/matc)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [<img src="https://avatars3.githubusercontent.com/u/7405702?v=3" width="110px;"/><br /><sub>Cole R. Davis</sub>](http://www.davisracingteam.com)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [<img src="https://avatars2.githubusercontent.com/u/10167681?v=3" width="110px;"/><br /><sub>gibsonjoshua55</sub>](https://github.com/gibsonjoshua55)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [<img src="https://avatars1.githubusercontent.com/u/6551003?v=4" width="110px;"/><br /><sub>Richard Hofman</sub>](https://github.com/richardhofman6)<br />[💻](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [<img src="https://avatars0.githubusercontent.com/u/3697569?v=4" width="110px;"/><br /><sub>gizzmojr</sub>](https://github.com/gizzmojr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [<img src="https://avatars3.githubusercontent.com/u/404729?v=4" width="110px;"/><br /><sub>Jenny Li</sub>](https://github.com/imjennyli)<br />[📖](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/869227?v=4" width="110px;"/><br /><sub>Geoff Young</sub>](https://github.com/GeoffYoung)<br />[💻](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [<img src="https://avatars3.githubusercontent.com/u/1068477?v=4" width="110px;"/><br /><sub>Elliot Blackburn</sub>](http://www.elliotblackburn.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") |
|
||||||
<tr>
|
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18545156?v=4" width="110px;"/><br /><sub>Lawrence</sub>](https://github.com/TheVakman)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>uknzaeinozpas</sub>](https://github.com/uknzaeinozpas)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [💻](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") | [<img src="https://avatars3.githubusercontent.com/u/422752?v=4" width="110px;"/><br /><sub>Ryan</sub>](https://github.com/Gelob)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Gelob "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/10672546?v=4" width="110px;"/><br /><sub>vcordes79</sub>](https://github.com/vcordes79)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vcordes79 "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kpawelski"><img src="https://avatars0.githubusercontent.com/u/10640152?v=3?s=110" width="110px;" alt="Karol"/><br /><sub><b>Karol</b></sub></a><br /><a href="#translation-kpawelski" title="Translation">🌍</a> <a href="https://github.com/snipe/snipe-it/commits?author=kpawelski" title="Code">💻</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/27958330?v=4" width="110px;"/><br /><sub>fordster78</sub>](https://github.com/fordster78)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [<img src="https://avatars0.githubusercontent.com/u/34064225?v=4" width="110px;"/><br /><sub>CronKz</sub>](https://github.com/CronKz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") [🌍](#translation-CronKz "Translation") | [<img src="https://avatars1.githubusercontent.com/u/585486?v=4" width="110px;"/><br /><sub>Tim Bishop</sub>](https://github.com/tdb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [<img src="https://avatars2.githubusercontent.com/u/5384694?v=4" width="110px;"/><br /><sub>Sean McIlvenna</sub>](https://www.seanmcilvenna.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [<img src="https://avatars3.githubusercontent.com/u/36515590?v=4" width="110px;"/><br /><sub>cepacs</sub>](https://github.com/cepacs)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [📖](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/37537300?v=4" width="110px;"/><br /><sub>lea-mink</sub>](https://github.com/lea-mink)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lea-mink "Code") | [<img src="https://avatars0.githubusercontent.com/u/7140719?v=4" width="110px;"/><br /><sub>Hannah Tinkler</sub>](https://github.com/hannahtinkler)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hannahtinkler "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://blog.morph027.de/"><img src="https://avatars3.githubusercontent.com/u/600106?v=3?s=110" width="110px;" alt="morph027"/><br /><sub><b>morph027</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=morph027" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/1086388?v=4" width="110px;"/><br /><sub>Doeke Zanstra</sub>](https://github.com/doekman)<br />[💻](https://github.com/snipe/snipe-it/commits?author=doekman "Code") | [<img src="https://avatars1.githubusercontent.com/u/4325936?v=4" width="110px;"/><br /><sub>Djamon Staal</sub>](https://www.sdhd.nl/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=SjamonDaal "Code") | [<img src="https://avatars3.githubusercontent.com/u/12306859?v=4" width="110px;"/><br /><sub>Earl Ramirez</sub>](https://github.com/EarlRamirez)<br />[💻](https://github.com/snipe/snipe-it/commits?author=EarlRamirez "Code") | [<img src="https://avatars2.githubusercontent.com/u/8671456?v=4" width="110px;"/><br /><sub>Richard Ray Thomas</sub>](https://github.com/RichardRay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=RichardRay "Code") | [<img src="https://avatars3.githubusercontent.com/u/1852688?v=4" width="110px;"/><br /><sub>Ryan Kuba</sub>](https://www.taisun.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thelamer "Code") | [<img src="https://avatars1.githubusercontent.com/u/6751928?v=4" width="110px;"/><br /><sub>Brian Monroe</sub>](https://github.com/ParadoxGuitarist)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ParadoxGuitarist "Code") | [<img src="https://avatars1.githubusercontent.com/u/605167?v=4" width="110px;"/><br /><sub>plexorama</sub>](https://github.com/plexorama)<br />[💻](https://github.com/snipe/snipe-it/commits?author=plexorama "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fvleminckx"><img src="https://avatars3.githubusercontent.com/u/22935755?v=3?s=110" width="110px;" alt="fvleminckx"/><br /><sub><b>fvleminckx</b></sub></a><br /><a href="#infra-fvleminckx" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/1795149?v=4" width="110px;"/><br /><sub>Till Deeke</sub>](https://tilldeeke.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tilldeeke "Code") | [<img src="https://avatars0.githubusercontent.com/u/12634129?v=4" width="110px;"/><br /><sub>5quirrel</sub>](https://github.com/5quirrel)<br />[💻](https://github.com/snipe/snipe-it/commits?author=5quirrel "Code") | [<img src="https://avatars1.githubusercontent.com/u/13071957?v=4" width="110px;"/><br /><sub>Jason</sub>](https://github.com/jasonlshelton)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonlshelton "Code") | [<img src="https://avatars3.githubusercontent.com/u/7128321?v=4" width="110px;"/><br /><sub>Antti</sub>](https://github.com/chemfy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chemfy "Code") | [<img src="https://avatars3.githubusercontent.com/u/10080364?v=4" width="110px;"/><br /><sub>DeusMaximus</sub>](https://github.com/DeusMaximus)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DeusMaximus "Code") | [<img src="https://avatars2.githubusercontent.com/u/16384611?v=4" width="110px;"/><br /><sub>a-royal</sub>](https://github.com/A-ROYAL)<br />[🌍](#translation-A-ROYAL "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5358208?v=4" width="110px;"/><br /><sub>Alberto Aldrigo</sub>](https://github.com/albertoaldrigo)<br />[🌍](#translation-albertoaldrigo "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/itsupportcmsukorg"><img src="https://avatars2.githubusercontent.com/u/15633547?v=3?s=110" width="110px;" alt="itsupportcmsukorg"/><br /><sub><b>itsupportcmsukorg</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=itsupportcmsukorg" title="Code">💻</a> <a href="https://github.com/snipe/snipe-it/issues?q=author%3Aitsupportcmsukorg" title="Bug reports">🐛</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/1412342?v=4" width="110px;"/><br /><sub>Alex Stanev</sub>](http://alex.stanev.org/blog)<br />[🌍](#translation-RealEnder "Translation") | [<img src="https://avatars0.githubusercontent.com/u/177295?v=4" width="110px;"/><br /><sub>Andreas Rehm</sub>](http://devel.itsolution2.de)<br />[🌍](#translation-sirrus "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5080535?v=4" width="110px;"/><br /><sub>Andreas Erhard</sub>](https://github.com/xelan)<br />[🌍](#translation-xelan "Translation") | [<img src="https://avatars2.githubusercontent.com/u/142350?v=4" width="110px;"/><br /><sub>Andrés Vanegas Jiménez</sub>](https://github.com/angeldeejay)<br />[🌍](#translation-angeldeejay "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3910403?v=4" width="110px;"/><br /><sub>Antonio Schiavon</sub>](https://github.com/aschiavon91)<br />[🌍](#translation-aschiavon91 "Translation") | [<img src="https://avatars0.githubusercontent.com/u/10464547?v=4" width="110px;"/><br /><sub>benunter</sub>](https://github.com/benunter)<br />[🌍](#translation-benunter "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5038647?v=4" width="110px;"/><br /><sub>Borys Żmuda</sub>](http://catweb24.pl)<br />[🌍](#translation-rudashi "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://override.io"><img src="https://avatars3.githubusercontent.com/u/12373799?v=3?s=110" width="110px;" alt="Frank"/><br /><sub><b>Frank</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=base-zero" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/5539359?v=4" width="110px;"/><br /><sub>chibacityblues</sub>](https://github.com/chibacityblues)<br />[🌍](#translation-chibacityblues "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1954830?v=4" width="110px;"/><br /><sub>Chien Wei Lin</sub>](https://github.com/cwlin0416)<br />[🌍](#translation-cwlin0416 "Translation") | [<img src="https://avatars3.githubusercontent.com/u/11700533?v=4" width="110px;"/><br /><sub>Christian Schuster</sub>](https://github.com/Againstreality)<br />[🌍](#translation-Againstreality "Translation") | [<img src="https://avatars1.githubusercontent.com/u/4308704?v=4" width="110px;"/><br /><sub>Christian Stefanus</sub>](http://chriss.webhostid.com)<br />[🌍](#translation-kopi-item "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3009327?v=4" width="110px;"/><br /><sub>wxcafé</sub>](http://wxcafe.net)<br />[🌍](#translation-wxcafe "Translation") | [<img src="https://avatars3.githubusercontent.com/u/35761525?v=4" width="110px;"/><br /><sub>dpyroc</sub>](https://github.com/dpyroc)<br />[🌍](#translation-dpyroc "Translation") | [<img src="https://avatars1.githubusercontent.com/u/2153639?v=4" width="110px;"/><br /><sub>Daniel Friedlmaier</sub>](http://www.friedlmaier.net)<br />[🌍](#translation-da-friedl "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ghost"><img src="https://avatars0.githubusercontent.com/u/10137?v=3?s=110" width="110px;" alt="Deleted user"/><br /><sub><b>Deleted user</b></sub></a><br /><a href="#translation-ghost" title="Translation">🌍</a> <a href="https://github.com/snipe/snipe-it/commits?author=ghost" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/2947640?v=4" width="110px;"/><br /><sub>Daniel Heene</sub>](https://github.com/danielheene)<br />[🌍](#translation-danielheene "Translation") | [<img src="https://avatars3.githubusercontent.com/u/319022?v=4" width="110px;"/><br /><sub>danielcb</sub>](https://github.com/danielcb)<br />[🌍](#translation-danielcb "Translation") | [<img src="https://avatars3.githubusercontent.com/u/15846537?v=4" width="110px;"/><br /><sub>Dominik Senti</sub>](https://github.com/dominiksenti)<br />[🌍](#translation-dominiksenti "Translation") | [<img src="https://avatars0.githubusercontent.com/u/25570954?v=4" width="110px;"/><br /><sub>Eric Gautheron</sub>](http://www.konectik.com)<br />[🌍](#translation-EpixFr "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5732623?v=4" width="110px;"/><br /><sub>Erlend Pilø</sub>](https://erlpil.com)<br />[🌍](#translation-Erlpil "Translation") | [<img src="https://avatars0.githubusercontent.com/u/541832?v=4" width="110px;"/><br /><sub>Fabio Rapposelli</sub>](http://fabio.technology)<br />[🌍](#translation-frapposelli "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3605240?v=4" width="110px;"/><br /><sub>Felipe Barros</sub>](https://github.com/fgbs)<br />[🌍](#translation-fgbs "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tiagom62"><img src="https://avatars1.githubusercontent.com/u/10802313?v=3?s=110" width="110px;" alt="tiagom62"/><br /><sub><b>tiagom62</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=tiagom62" title="Code">💻</a> <a href="#infra-tiagom62" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/257745?v=4" width="110px;"/><br /><sub>Fernando Possebon</sub>](https://github.com/possebon)<br />[🌍](#translation-possebon "Translation") | [<img src="https://avatars3.githubusercontent.com/u/2540832?v=4" width="110px;"/><br /><sub>gdraque</sub>](https://github.com/gdraque)<br />[🌍](#translation-gdraque "Translation") | [<img src="https://avatars0.githubusercontent.com/u/23440381?v=4" width="110px;"/><br /><sub>Georg Wallisch</sub>](https://github.com/georgwallisch)<br />[🌍](#translation-georgwallisch "Translation") | [<img src="https://avatars1.githubusercontent.com/u/9852832?v=4" width="110px;"/><br /><sub>Gerardo Robles</sub>](https://github.com/jgroblesr85)<br />[🌍](#translation-jgroblesr85 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/11082640?v=4" width="110px;"/><br /><sub>Gluek</sub>](https://t.me/Gluek)<br />[🌍](#translation-mrgluek "Translation") | [<img src="https://avatars0.githubusercontent.com/u/6847946?v=4" width="110px;"/><br /><sub>AdnanAbuShahad</sub>](https://github.com/AdnanAbuShahad)<br />[🌍](#translation-AdnanAbuShahad "Translation") | [<img src="https://avatars1.githubusercontent.com/u/3580608?v=4" width="110px;"/><br /><sub>Hafidzi My</sub>](https://hafidzi.my)<br />[🌍](#translation-hafidzi "Translation") |
|
||||||
</tr>
|
| [<img src="https://avatars2.githubusercontent.com/u/205521?v=4" width="110px;"/><br /><sub>Harim Park</sub>](https://github.com/fofwisdom)<br />[🌍](#translation-fofwisdom "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3333841?v=4" width="110px;"/><br /><sub>Henrik Kentsson</sub>](http://www.kentsson.se)<br />[🌍](#translation-Kentsson "Translation") | [<img src="https://avatars0.githubusercontent.com/u/36551034?v=4" width="110px;"/><br /><sub>Husnul Yaqien</sub>](https://github.com/husnulyaqien)<br />[🌍](#translation-husnulyaqien "Translation") | [<img src="https://avatars1.githubusercontent.com/u/2372747?v=4" width="110px;"/><br /><sub>Ibrahim</sub>](http://abaalkhail.org)<br />[🌍](#translation-abaalkh "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1389334?v=4" width="110px;"/><br /><sub>igolman</sub>](https://github.com/igolman)<br />[🌍](#translation-igolman "Translation") | [<img src="https://avatars1.githubusercontent.com/u/3257070?v=4" width="110px;"/><br /><sub>itangiang</sub>](https://github.com/itangiang)<br />[🌍](#translation-itangiang "Translation") | [<img src="https://avatars2.githubusercontent.com/u/14814254?v=4" width="110px;"/><br /><sub>jarby1211</sub>](https://github.com/jarby1211)<br />[🌍](#translation-jarby1211 "Translation") |
|
||||||
<tr>
|
| [<img src="https://avatars3.githubusercontent.com/u/6719357?v=4" width="110px;"/><br /><sub>Jhonn Willker</sub>](http://jwillker.com)<br />[🌍](#translation-JohnWillker "Translation") | [<img src="https://avatars2.githubusercontent.com/u/10983635?v=4" width="110px;"/><br /><sub>Jose</sub>](https://github.com/joxelito94)<br />[🌍](#translation-joxelito94 "Translation") | [<img src="https://avatars0.githubusercontent.com/u/5206122?v=4" width="110px;"/><br /><sub>laopangzi</sub>](https://github.com/laopangzi)<br />[🌍](#translation-laopangzi "Translation") | [<img src="https://avatars2.githubusercontent.com/u/79707?v=4" width="110px;"/><br /><sub>Lars Strojny</sub>](http://usrportage.de)<br />[🌍](#translation-lstrojny "Translation") | [<img src="https://avatars0.githubusercontent.com/u/389801?v=4" width="110px;"/><br /><sub>MarcosBL</sub>](http://twitter.com/marcosbl)<br />[🌍](#translation-MarcosBL "Translation") | [<img src="https://avatars3.githubusercontent.com/u/35664606?v=4" width="110px;"/><br /><sub>marie joy cajes</sub>](https://github.com/mariejoyacajes)<br />[🌍](#translation-mariejoyacajes "Translation") | [<img src="https://avatars2.githubusercontent.com/u/3052816?v=4" width="110px;"/><br /><sub>Mark S. Johansen</sub>](http://www.markjohansen.dk)<br />[🌍](#translation-msjohansen "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rystaf"><img src="https://avatars3.githubusercontent.com/u/2389047?v=3?s=110" width="110px;" alt="Ryan Stafford"/><br /><sub><b>Ryan Stafford</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rystaf" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/982885?v=4" width="110px;"/><br /><sub>Martin Stub</sub>](http://martinstub.dk)<br />[🌍](#translation-stubben "Translation") | [<img src="https://avatars2.githubusercontent.com/u/28959963?v=4" width="110px;"/><br /><sub>Meyer Flavio</sub>](https://github.com/meyerf99)<br />[🌍](#translation-meyerf99 "Translation") | [<img src="https://avatars3.githubusercontent.com/u/796443?v=4" width="110px;"/><br /><sub>Micael Rodrigues</sub>](https://github.com/MicaelRodrigues)<br />[🌍](#translation-MicaelRodrigues "Translation") | [<img src="https://avatars0.githubusercontent.com/u/10481331?v=4" width="110px;"/><br /><sub>Mikael Rasmussen</sub>](http://rubixy.com/)<br />[🌍](#translation-mikaelssen "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1544552?v=4" width="110px;"/><br /><sub>IxFail</sub>](https://github.com/IxFail)<br />[🌍](#translation-IxFail "Translation") | [<img src="https://avatars3.githubusercontent.com/u/18483118?v=4" width="110px;"/><br /><sub>Mohammed Fota</sub>](http://www.mohammedfota.com)<br />[🌍](#translation-MohammedFota "Translation") | [<img src="https://avatars0.githubusercontent.com/u/227080?v=4" width="110px;"/><br /><sub>Moayad Alserihi</sub>](https://github.com/omego)<br />[🌍](#translation-omego "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ehanlon"><img src="https://avatars2.githubusercontent.com/u/10345935?v=3?s=110" width="110px;" alt="Eammon Hanlon"/><br /><sub><b>Eammon Hanlon</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ehanlon" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/1680266?v=4" width="110px;"/><br /><sub>saymd</sub>](https://github.com/saymd)<br />[🌍](#translation-saymd "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1826808?v=4" width="110px;"/><br /><sub>Patrik Larsson</sub>](https://nordsken.se)<br />[🌍](#translation-pooot "Translation") | [<img src="https://avatars1.githubusercontent.com/u/20584746?v=4" width="110px;"/><br /><sub>drcryo</sub>](https://github.com/drcryo)<br />[🌍](#translation-drcryo "Translation") | [<img src="https://avatars1.githubusercontent.com/u/19408004?v=4" width="110px;"/><br /><sub>pawel1615</sub>](https://github.com/pawel1615)<br />[🌍](#translation-pawel1615 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/23340468?v=4" width="110px;"/><br /><sub>bodrovics</sub>](https://github.com/bodrovics)<br />[🌍](#translation-bodrovics "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3257654?v=4" width="110px;"/><br /><sub>priatna</sub>](https://github.com/priatna)<br />[🌍](#translation-priatna "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5358374?v=4" width="110px;"/><br /><sub>Fan Jiang</sub>](https://amayume.net)<br />[🌍](#translation-ProfFan "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zjean"><img src="https://avatars0.githubusercontent.com/u/441924?v=3?s=110" width="110px;" alt="zjean"/><br /><sub><b>zjean</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=zjean" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/22555451?v=4" width="110px;"/><br /><sub>ragnarcx</sub>](https://github.com/ragnarcx)<br />[🌍](#translation-ragnarcx "Translation") | [<img src="https://avatars2.githubusercontent.com/u/18654582?v=4" width="110px;"/><br /><sub>Rein van Haaren</sub>](http://www.reinvanhaaren.nl/)<br />[🌍](#translation-reinvanhaaren "Translation") | [<img src="https://avatars1.githubusercontent.com/u/386672?v=4" width="110px;"/><br /><sub>Teguh Dwicaksana</sub>](http://dheche.songolimo.net)<br />[🌍](#translation-dheche "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2572552?v=4" width="110px;"/><br /><sub>fraccie</sub>](https://github.com/FRaccie)<br />[🌍](#translation-FRaccie "Translation") | [<img src="https://avatars0.githubusercontent.com/u/35182720?v=4" width="110px;"/><br /><sub>vinzruzell</sub>](https://github.com/vinzruzell)<br />[🌍](#translation-vinzruzell "Translation") | [<img src="https://avatars1.githubusercontent.com/u/7883603?v=4" width="110px;"/><br /><sub>Kevin Austin</sub>](http://kevinaustin.com)<br />[🌍](#translation-vipsystem "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3861828?v=4" width="110px;"/><br /><sub>Wira Sandy</sub>](http://azuraweb.xyz)<br />[🌍](#translation-wira-sandy "Translation") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.frei.media"><img src="https://avatars0.githubusercontent.com/u/12660103?v=3?s=110" width="110px;" alt="Matthias Frei"/><br /><sub><b>Matthias Frei</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=FREImedia" title="Code">💻</a></td>
|
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [<img src="https://avatars1.githubusercontent.com/u/4930051?v=4" width="110px;"/><br /><sub>Wes Hulette</sub>](http://macfoo.wordpress.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jwhulette "Code") | [<img src="https://avatars0.githubusercontent.com/u/8134591?v=4" width="110px;"/><br /><sub>patrict</sub>](https://github.com/patrict)<br />[💻](https://github.com/snipe/snipe-it/commits?author=patrict "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/opsydev"><img src="https://avatars0.githubusercontent.com/u/3767518?v=3?s=110" width="110px;" alt="opsydev"/><br /><sub><b>opsydev</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=opsydev" title="Code">💻</a></td>
|
| [<img src="https://avatars3.githubusercontent.com/u/2611616?v=4" width="110px;"/><br /><sub>Dmitriy Minaev</sub>](https://github.com/VELIKII-DIVAN)<br />[💻](https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN "Code") | [<img src="https://avatars0.githubusercontent.com/u/5132245?v=4" width="110px;"/><br /><sub>liquidhorse</sub>](https://github.com/liquidhorse)<br />[💻](https://github.com/snipe/snipe-it/commits?author=liquidhorse "Code") | [<img src="https://avatars1.githubusercontent.com/u/183678?v=4" width="110px;"/><br /><sub>Jordi Boggiano</sub>](https://seld.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Seldaek "Code") | [<img src="https://avatars0.githubusercontent.com/u/653557?v=4" width="110px;"/><br /><sub>Ivan Nieto</sub>](https://github.com/inietov)<br />[💻](https://github.com/snipe/snipe-it/commits?author=inietov "Code") | [<img src="https://avatars2.githubusercontent.com/u/6764151?v=4" width="110px;"/><br /><sub>Ben RUBSON</sub>](https://github.com/benrubson)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benrubson "Code") | [<img src="https://avatars2.githubusercontent.com/u/8554558?v=4" width="110px;"/><br /><sub>NMathar</sub>](https://github.com/NMathar)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NMathar "Code") | [<img src="https://avatars1.githubusercontent.com/u/139566?v=4" width="110px;"/><br /><sub>Steffen</sub>](https://github.com/smb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=smb "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.ddreier.com"><img src="https://avatars1.githubusercontent.com/u/82290?v=3?s=110" width="110px;" alt="Daniel Dreier"/><br /><sub><b>Daniel Dreier</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=ddreier" title="Code">💻</a></td>
|
| [<img src="https://avatars0.githubusercontent.com/u/6609453?v=4" width="110px;"/><br /><sub>Sxderp</sub>](https://github.com/Sxderp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Sxderp "Code") | [<img src="https://avatars1.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>fanta8897</sub>](https://github.com/fanta8897)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fanta8897 "Code") | [<img src="https://avatars2.githubusercontent.com/u/2576509?v=4" width="110px;"/><br /><sub>Andrey Bolonin</sub>](https://andreybolonin.com/phpconsulting/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreybolonin "Code") | [<img src="https://avatars3.githubusercontent.com/u/2173307?v=4" width="110px;"/><br /><sub>shinayoshi</sub>](http://www.shinayoshi.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=shinayoshi "Code") | [<img src="https://avatars3.githubusercontent.com/u/2130159?v=4" width="110px;"/><br /><sub>Hubert</sub>](https://github.com/reuser)<br />[💻](https://github.com/snipe/snipe-it/commits?author=reuser "Code") | [<img src="https://avatars0.githubusercontent.com/u/6865789?v=4" width="110px;"/><br /><sub>KeenRivals</sub>](https://brashear.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KeenRivals "Code") | [<img src="https://avatars3.githubusercontent.com/u/2902513?v=4" width="110px;"/><br /><sub>omyno</sub>](https://github.com/omyno)<br />[💻](https://github.com/snipe/snipe-it/commits?author=omyno "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://rassie.org"><img src="https://avatars0.githubusercontent.com/u/23448?v=3?s=110" width="110px;" alt="Nikolai Prokoschenko"/><br /><sub><b>Nikolai Prokoschenko</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=rassie" title="Code">💻</a></td>
|
| [<img src="https://avatars1.githubusercontent.com/u/6271335?v=4" width="110px;"/><br /><sub>Evgeny</sub>](https://github.com/jackka)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jackka "Code") | [<img src="https://avatars2.githubusercontent.com/u/1169963?v=4" width="110px;"/><br /><sub>Colin Campbell</sub>](https://digitalist.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=colin-campbell "Code") | [<img src="https://avatars3.githubusercontent.com/u/2872098?v=4" width="110px;"/><br /><sub>Ľubomír Kučera</sub>](https://github.com/lubo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lubo "Code") | [<img src="https://avatars3.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://www.sourceguru.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Mezzle "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [<img src="https://avatars0.githubusercontent.com/u/17459600?v=4" width="110px;"/><br /><sub>Marián Skrip</sub>](https://github.com/mskrip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") | [<img src="https://avatars2.githubusercontent.com/u/47435081?v=4" width="110px;"/><br /><sub>Godfrey Martinez</sub>](https://github.com/Godmartinz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars1.githubusercontent.com/u/2075128?v=4" width="110px;"/><br /><sub>bigtreeEdo</sub>](https://github.com/bigtreeEdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [<img src="https://avatars0.githubusercontent.com/u/5000430?v=4" width="110px;"/><br /><sub>Colin McNeil</sub>](https://colinmcneil.me/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [<img src="https://avatars0.githubusercontent.com/u/421625?v=4" width="110px;"/><br /><sub>JoKneeMo</sub>](https://github.com/JoKneeMo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [<img src="https://avatars0.githubusercontent.com/u/54849013?v=4" width="110px;"/><br /><sub>Joshi</sub>](http://www.redbridge.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [<img src="https://avatars2.githubusercontent.com/u/15731458?v=4" width="110px;"/><br /><sub>Anthony Burns</sub>](https://github.com/anthonypburns)<br />[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [<img src="https://avatars1.githubusercontent.com/u/63399474?v=4" width="110px;"/><br /><sub>johnson-yi</sub>](https://github.com/johnson-yi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=johnson-yi "Code") | [<img src="https://avatars1.githubusercontent.com/u/1862720?v=4" width="110px;"/><br /><sub>Sanjay Govind</sub>](https://tangentmc.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sanjay900 "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars0.githubusercontent.com/u/1255375?v=4" width="110px;"/><br /><sub>Peter Upfold</sub>](https://peter.upfold.org.uk/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PeterUpfold "Code") | [<img src="https://avatars2.githubusercontent.com/u/961717?v=4" width="110px;"/><br /><sub>Jared Biel</sub>](https://github.com/jbiel)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jbiel "Code") | [<img src="https://avatars1.githubusercontent.com/u/1733625?v=4" width="110px;"/><br /><sub>Dampfklon</sub>](https://github.com/dampfklon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dampfklon "Code") | [<img src="https://avatars2.githubusercontent.com/u/52973156?v=4" width="110px;"/><br /><sub>Charles Hamilton</sub>](https://communityclosing.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chamilton-ccn "Code") | [<img src="https://avatars.githubusercontent.com/u/551789?v=4" width="110px;"/><br /><sub>Giuseppe Iannello</sub>](https://github.com/giannello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=giannello "Code") | [<img src="https://avatars.githubusercontent.com/u/3691490?v=4" width="110px;"/><br /><sub>Peter Dave Hello</sub>](https://www.peterdavehello.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PeterDaveHello "Code") | [<img src="https://avatars.githubusercontent.com/u/6106332?v=4" width="110px;"/><br /><sub>sigmoidal</sub>](https://github.com/sigmoidal)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sigmoidal "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YetAnotherCodeMonkey"><img src="https://avatars0.githubusercontent.com/u/13452757?v=3?s=110" width="110px;" alt="Drew"/><br /><sub><b>Drew</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=YetAnotherCodeMonkey" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/2082554?v=4" width="110px;"/><br /><sub>Vincent Lainé</sub>](https://github.com/phenixdotnet)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phenixdotnet "Code") | [<img src="https://avatars.githubusercontent.com/u/1943040?v=4" width="110px;"/><br /><sub>Lucas Pleß</sub>](http://www.lucas-pless.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derlucas "Code") | [<img src="https://avatars.githubusercontent.com/u/472804?v=4" width="110px;"/><br /><sub>Ian Littman</sub>](http://twitter.com/iansltx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=iansltx "Code") | [<img src="https://avatars.githubusercontent.com/u/3519029?v=4" width="110px;"/><br /><sub>João Paulo</sub>](https://github.com/PauloLuna)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PauloLuna "Code") | [<img src="https://avatars.githubusercontent.com/u/70443365?v=4" width="110px;"/><br /><sub>ThoBur</sub>](https://github.com/ThoBur)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ThoBur "Code") | [<img src="https://avatars.githubusercontent.com/u/1972329?v=4" width="110px;"/><br /><sub>Alexander Chibrikin</sub>](http://phpprofi.ru/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alek13 "Code") | [<img src="https://avatars.githubusercontent.com/u/438332?v=4" width="110px;"/><br /><sub>Anthony Winstanley</sub>](https://github.com/winstan)<br />[💻](https://github.com/snipe/snipe-it/commits?author=winstan "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/merid14"><img src="https://avatars0.githubusercontent.com/u/1342320?v=3?s=110" width="110px;" alt="Walter"/><br /><sub><b>Walter</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=merid14" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/3075214?v=4" width="110px;"/><br /><sub>Folke</sub>](https://github.com/fashberg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fashberg "Code") | [<img src="https://avatars.githubusercontent.com/u/1351571?v=4" width="110px;"/><br /><sub>Bennett Blodinger</sub>](https://github.com/benwa)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benwa "Code") | [<img src="https://avatars.githubusercontent.com/u/2974631?v=4" width="110px;"/><br /><sub>NMC</sub>](https://nmc.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ncareau "Code") | [<img src="https://avatars.githubusercontent.com/u/52182449?v=4" width="110px;"/><br /><sub>andres-baller</sub>](https://github.com/andres-baller)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andres-baller "Code") | [<img src="https://avatars.githubusercontent.com/u/67109348?v=4" width="110px;"/><br /><sub>sean-borg</sub>](https://github.com/sean-borg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sean-borg "Code") | [<img src="https://avatars.githubusercontent.com/u/32170051?v=4" width="110px;"/><br /><sub>EDVLeer</sub>](https://github.com/EDVLeer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=EDVLeer "Code") | [<img src="https://avatars.githubusercontent.com/u/23075196?v=4" width="110px;"/><br /><sub>Kurokat</sub>](https://github.com/Kurokat)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Kurokat "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/balous"><img src="https://avatars3.githubusercontent.com/u/11254614?v=3?s=110" width="110px;" alt="Petr Baloun"/><br /><sub><b>Petr Baloun</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=balous" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/915514?v=4" width="110px;"/><br /><sub>Kevin Köllmann</sub>](https://www.kevinkoellmann.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koelle25 "Code") | [<img src="https://avatars.githubusercontent.com/u/49025941?v=4" width="110px;"/><br /><sub>sw-mreyes</sub>](https://github.com/sw-mreyes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sw-mreyes "Code") | [<img src="https://avatars.githubusercontent.com/u/70129?v=4" width="110px;"/><br /><sub>Joel Pittet</sub>](https://pittet.ca)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joelpittet "Code") | [<img src="https://avatars.githubusercontent.com/u/792695?v=4" width="110px;"/><br /><sub>Eli Young</sub>](https://elyscape.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=elyscape "Code") | [<img src="https://avatars.githubusercontent.com/u/317015?v=4" width="110px;"/><br /><sub>Raell Dottin</sub>](https://github.com/raelldottin)<br />[💻](https://github.com/snipe/snipe-it/commits?author=raelldottin "Code") | [<img src="https://avatars.githubusercontent.com/u/1446856?v=4" width="110px;"/><br /><sub>Tom Misilo</sub>](https://github.com/misilot)<br />[💻](https://github.com/snipe/snipe-it/commits?author=misilot "Code") | [<img src="https://avatars.githubusercontent.com/u/4496300?v=4" width="110px;"/><br /><sub>David Davenne</sub>](http://david.davenne.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JuustoMestari "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/reidblomquist"><img src="https://avatars0.githubusercontent.com/u/6117660?v=3?s=110" width="110px;" alt="reidblomquist"/><br /><sub><b>reidblomquist</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=reidblomquist" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mathieuk"><img src="https://avatars0.githubusercontent.com/u/539914?v=3?s=110" width="110px;" alt="Mathieu Kooiman"/><br /><sub><b>Mathieu Kooiman</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=mathieuk" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/csayre"><img src="https://avatars3.githubusercontent.com/u/6606421?v=3?s=110" width="110px;" alt="csayre"/><br /><sub><b>csayre</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=csayre" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [<img src="https://avatars.githubusercontent.com/u/11973217?v=4" width="110px;"/><br /><sub>tbrconnect</sub>](https://github.com/tbrconnect)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") | [<img src="https://avatars.githubusercontent.com/u/12447225?v=4" width="110px;"/><br /><sub>kcoyo</sub>](https://github.com/kcoyo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kcoyo "Code") | [<img src="https://avatars.githubusercontent.com/u/494017?v=4" width="110px;"/><br /><sub>Travis Miller</sub>](https://travismiller.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=travismiller "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/adamdunson"><img src="https://avatars1.githubusercontent.com/u/768488?v=3?s=110" width="110px;" alt="Adam Dunson"/><br /><sub><b>Adam Dunson</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=adamdunson" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
|
||||||
</tr>
|
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
|
||||||
<tr>
|
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/thehereward"><img src="https://avatars0.githubusercontent.com/u/5547470?v=3?s=110" width="110px;" alt="Hereward"/><br /><sub><b>Hereward</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=thehereward" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/swoopdk"><img src="https://avatars0.githubusercontent.com/u/5802977?v=3?s=110" width="110px;" alt="swoopdk"/><br /><sub><b>swoopdk</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=swoopdk" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://linkedin.com/in/ahimta"><img src="https://avatars1.githubusercontent.com/u/3470403?v=3?s=110" width="110px;" alt="Abdullah Alansari"/><br /><sub><b>Abdullah Alansari</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Ahimta" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MicaelRodrigues"><img src="https://avatars0.githubusercontent.com/u/796443?v=3?s=110" width="110px;" alt="Micael Rodrigues"/><br /><sub><b>Micael Rodrigues</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=MicaelRodrigues" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://macadmincorner.com"><img src="https://avatars0.githubusercontent.com/u/614564?v=3?s=110" width="110px;" alt="Patrick Gallagher"/><br /><sub><b>Patrick Gallagher</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=patgmac" title="Documentation">📖</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Miliamber"><img src="https://avatars3.githubusercontent.com/u/7165922?v=3?s=110" width="110px;" alt="Miliamber"/><br /><sub><b>Miliamber</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=Miliamber" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hawk554"><img src="https://avatars3.githubusercontent.com/u/861766?v=3?s=110" width="110px;" alt="hawk554"/><br /><sub><b>hawk554</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=hawk554" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
</tr>
|
| [<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") |
|
||||||
<tr>
|
| [<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") |
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jbirdkerr.net"><img src="https://avatars1.githubusercontent.com/u/1695622?v=3?s=110" width="110px;" alt="Justin Kerr"/><br /><sub><b>Justin Kerr</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=jbirdkerr" title="Code">💻</a></td>
|
| [<img src="https://avatars.githubusercontent.com/u/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") |
|
||||||
<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/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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bilias"><img src="https://avatars.githubusercontent.com/u/47315739?v=4?s=110" width="110px;" alt="bilias"/><br /><sub><b>bilias</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=bilias" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coach1988"><img src="https://avatars.githubusercontent.com/u/2565989?v=4?s=110" width="110px;" alt="coach1988"/><br /><sub><b>coach1988</b></sub></a><br /><a href="https://github.com/snipe/snipe-it/commits?author=coach1988" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/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>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||||
|
|
|
@ -105,7 +105,7 @@ RUN \
|
||||||
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
|
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
|
||||||
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
|
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
|
||||||
&& chown docker "/var/lib/snipeit/keys/" \
|
&& chown docker "/var/lib/snipeit/keys/" \
|
||||||
&& chown -h docker "/var/www/html/storage/" \
|
&& chown -Rh docker "/var/www/html/storage/" \
|
||||||
&& chmod +x /var/www/html/artisan \
|
&& chmod +x /var/www/html/artisan \
|
||||||
&& echo "Finished setting up application in /var/www/html"
|
&& echo "Finished setting up application in /var/www/html"
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
![snipe-it-by-grok](https://github.com/snipe/snipe-it/assets/197404/b515673b-c7c8-4d9a-80f5-9fa58829a602)
|
![snipe-it-by-grok](https://github.com/snipe/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/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&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/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![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)
|
||||||
[![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)
|
[![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
|
## Snipe-IT - Open Source Asset Management System
|
||||||
|
|
||||||
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
|
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
|
||||||
|
|
||||||
It is built on [Laravel 8](http://laravel.com).
|
It is built on [Laravel 10](http://laravel.com).
|
||||||
|
|
||||||
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
||||||
|
|
||||||
> [!TIP]
|
> [!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, 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.
|
> __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.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
8
app.json
8
app.json
|
@ -38,7 +38,7 @@
|
||||||
"description": "The maximum number of search results that can be returned at one time.",
|
"description": "The maximum number of search results that can be returned at one time.",
|
||||||
"value": "500"
|
"value": "500"
|
||||||
},
|
},
|
||||||
"MAIL_DRIVER": {
|
"MAIL_MAILER": {
|
||||||
"description": "Mail driver - Generally SMTP on Heroku - https://snipe-it.readme.io/docs/configuration#required-outgoing-mail-settings",
|
"description": "Mail driver - Generally SMTP on Heroku - https://snipe-it.readme.io/docs/configuration#required-outgoing-mail-settings",
|
||||||
"value": "smtp"
|
"value": "smtp"
|
||||||
},
|
},
|
||||||
|
@ -58,9 +58,9 @@
|
||||||
"description": "SMTP Server Password",
|
"description": "SMTP Server Password",
|
||||||
"value": "YOURPASSWORD"
|
"value": "YOURPASSWORD"
|
||||||
},
|
},
|
||||||
"MAIL_ENCRYPTION": {
|
"MAIL_TLS_VERIFY_PEER": {
|
||||||
"description": "Encryption protocol for email sending.",
|
"description": "Ensure validity of TLS certificate on remote mail server",
|
||||||
"value": "null"
|
"value": true
|
||||||
},
|
},
|
||||||
"MAIL_FROM_ADDR": {
|
"MAIL_FROM_ADDR": {
|
||||||
"description": "Email from address",
|
"description": "Email from address",
|
||||||
|
|
|
@ -7,7 +7,7 @@ use Illuminate\Console\Command;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Laravel\Passport\TokenRepository;
|
use Laravel\Passport\TokenRepository;
|
||||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class GeneratePersonalAccessToken extends Command
|
class GeneratePersonalAccessToken extends Command
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Models\Setting;
|
||||||
use App\Models\Ldap;
|
use App\Models\Ldap;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class LdapSync extends Command
|
class LdapSync extends Command
|
||||||
{
|
{
|
||||||
|
@ -251,6 +251,7 @@ class LdapSync extends Command
|
||||||
// Creating a new user.
|
// Creating a new user.
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->password = $user->noPassword();
|
$user->password = $user->noPassword();
|
||||||
|
$user->locale = app()->getLocale();
|
||||||
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
||||||
$item['createorupdate'] = 'created';
|
$item['createorupdate'] = 'created';
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,7 @@ class LdapSync extends Command
|
||||||
try {
|
try {
|
||||||
$ldap_manager = Ldap::findLdapUsers($item['manager'], -1, $this->option('filter'));
|
$ldap_manager = Ldap::findLdapUsers($item['manager'], -1, $this->option('filter'));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::warning("Manager lookup caused an exception: " . $e->getMessage() . ". Falling back to direct username lookup");
|
Log::warning("Manager lookup caused an exception: " . $e->getMessage() . ". Falling back to direct username lookup");
|
||||||
// Hail-mary for Okta manager 'shortnames' - will only work if
|
// Hail-mary for Okta manager 'shortnames' - will only work if
|
||||||
// Okta configuration is using full email-address-style usernames
|
// Okta configuration is using full email-address-style usernames
|
||||||
$ldap_manager = [
|
$ldap_manager = [
|
||||||
|
@ -390,7 +391,7 @@ class LdapSync extends Command
|
||||||
$user->location_id = $location->id;
|
$user->location_id = $location->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$location = null;
|
||||||
$user->ldap_import = 1;
|
$user->ldap_import = 1;
|
||||||
|
|
||||||
$errors = '';
|
$errors = '';
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given ip is in a network
|
* Check if a given ip is in a network
|
||||||
|
@ -160,7 +160,7 @@ class LdapTroubleshooter extends Command
|
||||||
$output[] = "-x";
|
$output[] = "-x";
|
||||||
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
||||||
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
||||||
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
|
$output[] = "-w ".escapeshellarg(Crypt::Decrypt($settings->ldap_pword));
|
||||||
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
|
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
|
||||||
if($settings->ldap_tls) {
|
if($settings->ldap_tls) {
|
||||||
$this->line("# adding STARTTLS option");
|
$this->line("# adding STARTTLS option");
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Events\UserMerged;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
@ -51,7 +52,7 @@ class MergeUsersByUsername extends Command
|
||||||
|
|
||||||
$bad_users = User::where('username', '=', trim($parts[0]))
|
$bad_users = User::where('username', '=', trim($parts[0]))
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
|
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,10 +106,26 @@ class MergeUsersByUsername extends Command
|
||||||
$managedLocation->save();
|
$managedLocation->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($bad_user->uploads as $upload) {
|
||||||
|
$this->info('Updating upload log record '.$upload->id.' to user '.$user->id);
|
||||||
|
$upload->item_id = $user->id;
|
||||||
|
$upload->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($bad_user->acceptances as $acceptance) {
|
||||||
|
$this->info('Updating acceptance log record '.$acceptance->id.' to user '.$user->id);
|
||||||
|
$acceptance->item_id = $user->id;
|
||||||
|
$acceptance->save();
|
||||||
|
}
|
||||||
|
|
||||||
// Mark the user as deleted
|
// Mark the user as deleted
|
||||||
$this->info('Marking the user as deleted');
|
$this->info('Marking the user as deleted');
|
||||||
$bad_user->deleted_at = Carbon::now()->timestamp;
|
$bad_user->deleted_at = Carbon::now()->timestamp;
|
||||||
$bad_user->save();
|
$bad_user->save();
|
||||||
|
|
||||||
|
event(new UserMerged($bad_user, $user, null));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class MoveUploadsToNewDisk extends Command
|
class MoveUploadsToNewDisk extends Command
|
||||||
{
|
{
|
||||||
|
@ -74,7 +75,7 @@ class MoveUploadsToNewDisk extends Command
|
||||||
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
|
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
|
||||||
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
|
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ class MoveUploadsToNewDisk extends Command
|
||||||
$new_url = Storage::url($private_type . '/' . $filename, $filename);
|
$new_url = Storage::url($private_type . '/' . $filename, $filename);
|
||||||
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
|
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +141,7 @@ class MoveUploadsToNewDisk extends Command
|
||||||
unlink($filename);
|
unlink($filename);
|
||||||
$public_delete_count++;
|
$public_delete_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +154,7 @@ class MoveUploadsToNewDisk extends Command
|
||||||
unlink($filename);
|
unlink($filename);
|
||||||
$private_delete_count++;
|
$private_delete_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
$this->error($e);
|
$this->error($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Console\Commands;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
|
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
|
||||||
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
|
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
|
||||||
|
@ -59,7 +60,7 @@ class ObjectImportCommand extends Command
|
||||||
|
|
||||||
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
|
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
|
||||||
// $logFile = $this->option('logfile');
|
// $logFile = $this->option('logfile');
|
||||||
// \Log::useFiles($logFile);
|
// Log::useFiles($logFile);
|
||||||
$this->comment('======= Importing Items from '.$filename.' =========');
|
$this->comment('======= Importing Items from '.$filename.' =========');
|
||||||
$importer->import();
|
$importer->import();
|
||||||
|
|
||||||
|
@ -112,10 +113,10 @@ class ObjectImportCommand extends Command
|
||||||
public function log($string, $level = 'info')
|
public function log($string, $level = 'info')
|
||||||
{
|
{
|
||||||
if ($level === 'warning') {
|
if ($level === 'warning') {
|
||||||
\Log::warning($string);
|
Log::warning($string);
|
||||||
$this->comment($string);
|
$this->comment($string);
|
||||||
} else {
|
} else {
|
||||||
\Log::Info($string);
|
Log::Info($string);
|
||||||
if ($this->option('verbose')) {
|
if ($this->option('verbose')) {
|
||||||
$this->comment($string);
|
$this->comment($string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use Schema;
|
use Schema;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class PaveIt extends Command
|
class PaveIt extends Command
|
||||||
|
|
|
@ -103,7 +103,7 @@ class RecryptFromMcrypt extends Command
|
||||||
$this->comment('INFO: No LDAP password found. Skipping... ');
|
$this->comment('INFO: No LDAP password found. Skipping... ');
|
||||||
} else {
|
} else {
|
||||||
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
|
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
|
||||||
$settings->ldap_pword = \Crypt::encrypt($decrypted_ldap_pword);
|
$settings->ldap_pword = Crypt::encrypt($decrypted_ldap_pword);
|
||||||
$settings->save();
|
$settings->save();
|
||||||
}
|
}
|
||||||
/** @var CustomField[] $custom_fields */
|
/** @var CustomField[] $custom_fields */
|
||||||
|
@ -132,7 +132,7 @@ class RecryptFromMcrypt extends Command
|
||||||
// Try to decrypt the payload using the legacy app key
|
// Try to decrypt the payload using the legacy app key
|
||||||
try {
|
try {
|
||||||
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
|
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
|
||||||
$asset->{$columnName} = \Crypt::encrypt($decrypted_field);
|
$asset->{$columnName} = Crypt::encrypt($decrypted_field);
|
||||||
$this->comment($decrypted_field);
|
$this->comment($decrypted_field);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class RegenerateAssetTags extends Command
|
class RegenerateAssetTags extends Command
|
||||||
|
|
|
@ -6,8 +6,8 @@ use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class RestoreDeletedUsers extends Command
|
class RestoreDeletedUsers extends Command
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class SQLStreamer {
|
class SQLStreamer {
|
||||||
private $input;
|
private $input;
|
||||||
|
@ -125,7 +126,7 @@ class SQLStreamer {
|
||||||
while (($buffer = fgets($this->input, SQLStreamer::$buffer_size)) !== false) {
|
while (($buffer = fgets($this->input, SQLStreamer::$buffer_size)) !== false) {
|
||||||
$bytes_read += strlen($buffer);
|
$bytes_read += strlen($buffer);
|
||||||
if ($this->reading_beginning_of_line) {
|
if ($this->reading_beginning_of_line) {
|
||||||
// \Log::debug("Buffer is: '$buffer'");
|
// Log::debug("Buffer is: '$buffer'");
|
||||||
$cleaned_buffer = $this->parse_sql($buffer);
|
$cleaned_buffer = $this->parse_sql($buffer);
|
||||||
if ($this->output) {
|
if ($this->output) {
|
||||||
$bytes_written = fwrite($this->output, $cleaned_buffer);
|
$bytes_written = fwrite($this->output, $cleaned_buffer);
|
||||||
|
@ -191,7 +192,7 @@ class RestoreFromBackup extends Command
|
||||||
{
|
{
|
||||||
$dir = getcwd();
|
$dir = getcwd();
|
||||||
if( $dir != base_path() ) { // usually only the case when running via webserver, not via command-line
|
if( $dir != base_path() ) { // usually only the case when running via webserver, not via command-line
|
||||||
\Log::debug("Current working directory is: $dir, changing directory to: ".base_path());
|
Log::debug("Current working directory is: $dir, changing directory to: ".base_path());
|
||||||
chdir(base_path()); // TODO - is this *safe* to change on a running script?!
|
chdir(base_path()); // TODO - is this *safe* to change on a running script?!
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
@ -297,7 +298,7 @@ class RestoreFromBackup extends Command
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
|
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
|
||||||
\Log::debug("Found a sql file!");
|
Log::debug("Found a sql file!");
|
||||||
$sqlfiles[] = $raw_path;
|
$sqlfiles[] = $raw_path;
|
||||||
$sqlfile_indices[] = $i;
|
$sqlfile_indices[] = $i;
|
||||||
continue;
|
continue;
|
||||||
|
@ -413,7 +414,7 @@ class RestoreFromBackup extends Command
|
||||||
$bytes_read = 0;
|
$bytes_read = 0;
|
||||||
while (($buffer = fgets($sql_contents, SQLStreamer::$buffer_size)) !== false) {
|
while (($buffer = fgets($sql_contents, SQLStreamer::$buffer_size)) !== false) {
|
||||||
$bytes_read += strlen($buffer);
|
$bytes_read += strlen($buffer);
|
||||||
// \Log::debug("Buffer is: '$buffer'");
|
// Log::debug("Buffer is: '$buffer'");
|
||||||
$bytes_written = fwrite($pipes[0], $buffer);
|
$bytes_written = fwrite($pipes[0], $buffer);
|
||||||
|
|
||||||
if ($bytes_written === false) {
|
if ($bytes_written === false) {
|
||||||
|
@ -425,13 +426,13 @@ class RestoreFromBackup extends Command
|
||||||
$bytes_read = $sql_importer->line_aware_piping();
|
$bytes_read = $sql_importer->line_aware_piping();
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
Log::error("Error during restore!!!! ".$e->getMessage());
|
||||||
// FIXME - put these back and/or put them in the right places?!
|
// FIXME - put these back and/or put them in the right places?!
|
||||||
$err_out = fgets($pipes[1]);
|
$err_out = fgets($pipes[1]);
|
||||||
$err_err = fgets($pipes[2]);
|
$err_err = fgets($pipes[2]);
|
||||||
\Log::error("Error OUTPUT: ".$err_out);
|
Log::error("Error OUTPUT: ".$err_out);
|
||||||
$this->info($err_out);
|
$this->info($err_out);
|
||||||
\Log::error("Error ERROR : ".$err_err);
|
Log::error("Error ERROR : ".$err_err);
|
||||||
$this->error($err_err);
|
$this->error($err_err);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Illuminate\Encryption\Encrypter;
|
use Illuminate\Encryption\Encrypter;
|
||||||
|
|
105
app/Console/Commands/SendAcceptanceReminder.php
Normal file
105
app/Console/Commands/SendAcceptanceReminder.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\CheckoutAcceptance;
|
||||||
|
use App\Models\Setting;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Notifications\CheckoutAssetNotification;
|
||||||
|
use App\Notifications\CurrentInventory;
|
||||||
|
use App\Notifications\UnacceptedAssetReminderNotification;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
|
class SendAcceptanceReminder extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'snipeit:acceptance-reminder';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'This will resend users with unaccepted assets a reminder to accept or decline them.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$pending = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')
|
||||||
|
->whereHas('checkoutable', function($query) {
|
||||||
|
$query->where('archived', 0);
|
||||||
|
})
|
||||||
|
->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model', 'checkoutable.adminuser'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$unacceptedAssetGroups = $pending
|
||||||
|
->filter(function($acceptance) {
|
||||||
|
return $acceptance->checkoutable_type == 'App\Models\Asset';
|
||||||
|
})
|
||||||
|
->map(function($acceptance) {
|
||||||
|
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
|
||||||
|
})
|
||||||
|
->groupBy(function($item) {
|
||||||
|
return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$no_mail_address = [];
|
||||||
|
|
||||||
|
foreach($unacceptedAssetGroups as $unacceptedAssetGroup) {
|
||||||
|
$item_count = $unacceptedAssetGroup->count();
|
||||||
|
foreach ($unacceptedAssetGroup as $unacceptedAsset) {
|
||||||
|
// if ($unacceptedAsset['acceptance']->assignedTo->email == ''){
|
||||||
|
// $no_mail_address[] = $unacceptedAsset['checkoutable']->assignedTo->present()->fullName;
|
||||||
|
// }
|
||||||
|
if ($unacceptedAsset['acceptance']->assignedTo) {
|
||||||
|
|
||||||
|
if (!$unacceptedAsset['acceptance']->assignedTo->locale) {
|
||||||
|
Notification::locale(Setting::getSettings()->locale)->send(
|
||||||
|
$unacceptedAsset['acceptance']->assignedTo,
|
||||||
|
new UnacceptedAssetReminderNotification($unacceptedAsset['assetItem'], $count)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Notification::send(
|
||||||
|
$unacceptedAsset['acceptance']->assignedTo,
|
||||||
|
new UnacceptedAssetReminderNotification($unacceptedAsset, $item_count)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($no_mail_address)) {
|
||||||
|
foreach($no_mail_address as $user) {
|
||||||
|
return $user.' has no email.';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$this->info($count.' users notified.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ class SendCurrentInventoryToUsers extends Command
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0)) {
|
if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0) || ($user->consumables->count() > 0)) {
|
||||||
$count++;
|
$count++;
|
||||||
$user->notify((new CurrentInventory($user)));
|
$user->notify((new CurrentInventory($user)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use App\Notifications\ExpectedCheckinAdminNotification;
|
||||||
use App\Notifications\ExpectedCheckinNotification;
|
use App\Notifications\ExpectedCheckinNotification;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class SendExpectedCheckinAlerts extends Command
|
class SendExpectedCheckinAlerts extends Command
|
||||||
{
|
{
|
||||||
|
@ -43,25 +42,31 @@ class SendExpectedCheckinAlerts extends Command
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$whenNotify = Carbon::now();
|
$interval = $settings->audit_warning_days ?? 0;
|
||||||
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
$today = Carbon::now();
|
||||||
|
$interval_date = $today->copy()->addDays($interval);
|
||||||
|
|
||||||
|
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForCheckin($settings)->orderBy('assets.expected_checkin', 'desc')->get();
|
||||||
|
|
||||||
|
$this->info($assets->count().' assets must be checked in on or before '.$interval_date.' is deadline');
|
||||||
|
|
||||||
$this->info($whenNotify.' is deadline');
|
|
||||||
$this->info($assets->count().' assets');
|
|
||||||
|
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
if ($asset->assigned && $asset->checkedOutToUser()) {
|
if ($asset->assignedTo && (isset($asset->assignedTo->email)) && ($asset->assignedTo->email!='') && $asset->checkedOutToUser()) {
|
||||||
Log::info('Sending ExpectedCheckinNotification to ' . $asset->assigned->email);
|
$this->info('Sending User ExpectedCheckinNotification to: '.$asset->assignedTo->email);
|
||||||
$asset->assigned->notify((new ExpectedCheckinNotification($asset)));
|
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
||||||
// Send a rollup to the admin, if settings dictate
|
// Send a rollup to the admin, if settings dictate
|
||||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
|
||||||
return new AlertRecipient($item);
|
return new AlertRecipient($item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->info('Sending Admin ExpectedCheckinNotification to: '.$settings->alert_email);
|
||||||
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
|
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\License;
|
use App\Models\Recipients\AlertRecipient;
|
||||||
use App\Models\Recipients;
|
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Notifications\ExpiringAssetsNotification;
|
|
||||||
use App\Notifications\SendUpcomingAuditNotification;
|
use App\Notifications\SendUpcomingAuditNotification;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SendUpcomingAuditReport extends Command
|
class SendUpcomingAuditReport extends Command
|
||||||
|
@ -46,39 +44,24 @@ class SendUpcomingAuditReport extends Command
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
$interval = $settings->audit_warning_days ?? 0;
|
||||||
|
$today = Carbon::now();
|
||||||
|
$interval_date = $today->copy()->addDays($interval);
|
||||||
|
|
||||||
if (($settings->alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) {
|
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
|
||||||
|
$this->info($assets->count().' assets must be audited in on or before '.$interval_date.' is deadline');
|
||||||
|
|
||||||
|
|
||||||
|
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
||||||
// Send a rollup to the admin, if settings dictate
|
// Send a rollup to the admin, if settings dictate
|
||||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
|
||||||
return new \App\Models\Recipients\AlertRecipient($item);
|
return new AlertRecipient($item);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assets due for auditing
|
$this->info('Sending Admin SendUpcomingAuditNotification to: '.$settings->alert_email);
|
||||||
|
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
|
||||||
|
|
||||||
$assets = Asset::whereNotNull('next_audit_date')
|
|
||||||
->DueOrOverdueForAudit($settings)
|
|
||||||
->orderBy('last_audit_date', 'asc')->get();
|
|
||||||
|
|
||||||
if ($assets->count() > 0) {
|
|
||||||
$this->info(trans_choice('mail.upcoming-audits', $assets->count(),
|
|
||||||
['count' => $assets->count(), 'threshold' => $settings->audit_warning_days]));
|
|
||||||
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
|
|
||||||
$this->info('Audit report sent to '.$settings->alert_email);
|
|
||||||
} else {
|
|
||||||
$this->info('No assets to be audited. No report sent.');
|
|
||||||
}
|
|
||||||
} elseif ($settings->alert_email == '') {
|
|
||||||
$this->error('Could not send email. No alert email configured in settings');
|
|
||||||
} elseif (! $settings->audit_warning_days) {
|
|
||||||
$this->error('No audit warning days set in Admin Notifications. No mail will be sent.');
|
|
||||||
} elseif ($settings->alerts_enabled != 1) {
|
|
||||||
$this->info('Alerts are disabled in the settings. No mail will be sent');
|
|
||||||
} else {
|
|
||||||
$this->error('Something went wrong. :( ');
|
|
||||||
$this->error('Admin Notifications Email Setting: '.$settings->alert_email);
|
|
||||||
$this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days);
|
|
||||||
$this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class SyncAssetCounters extends Command
|
class SyncAssetCounters extends Command
|
||||||
{
|
{
|
||||||
|
@ -58,7 +59,7 @@ class SyncAssetCounters extends Command
|
||||||
$asset->save();
|
$asset->save();
|
||||||
$bar->advance();
|
$bar->advance();
|
||||||
|
|
||||||
\Log::debug('Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests');
|
Log::debug('Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class UserMerged
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(User $from_user, User $to_user, User $admin)
|
public function __construct(User $from_user, User $to_user, ?User $admin)
|
||||||
{
|
{
|
||||||
$this->merged_from = $from_user;
|
$this->merged_from = $from_user;
|
||||||
$this->merged_to = $to_user;
|
$this->merged_to = $to_user;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use App\Helpers\Helper;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
|
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use JsonException;
|
use JsonException;
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
|
@ -44,8 +44,8 @@ class Handler extends ExceptionHandler
|
||||||
public function report(Throwable $exception)
|
public function report(Throwable $exception)
|
||||||
{
|
{
|
||||||
if ($this->shouldReport($exception)) {
|
if ($this->shouldReport($exception)) {
|
||||||
if (class_exists(\Log::class)) {
|
if (class_exists(Log::class)) {
|
||||||
\Log::error($exception);
|
Log::error($exception);
|
||||||
}
|
}
|
||||||
return parent::report($exception);
|
return parent::report($exception);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,12 @@ use App\Models\Depreciation;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\Statuslabel;
|
use App\Models\Statuslabel;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Image;
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Intervention\Image\ImageManagerStatic as Image;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class Helper
|
class Helper
|
||||||
{
|
{
|
||||||
|
@ -62,6 +64,7 @@ class Helper
|
||||||
'nl' => 'nl-NL', // Dutch
|
'nl' => 'nl-NL', // Dutch
|
||||||
'no' => 'no-NO', // Norwegian
|
'no' => 'no-NO', // Norwegian
|
||||||
'pl' => 'pl-PL', // Polish
|
'pl' => 'pl-PL', // Polish
|
||||||
|
'pt' => 'pt-PT', // Portuguese
|
||||||
'ro' => 'ro-RO', // Romanian
|
'ro' => 'ro-RO', // Romanian
|
||||||
'ru' => 'ru-RU', // Russian
|
'ru' => 'ru-RU', // Russian
|
||||||
'sk' => 'sk-SK', // Slovak
|
'sk' => 'sk-SK', // Slovak
|
||||||
|
@ -412,7 +415,7 @@ class Helper
|
||||||
|
|
||||||
if ($index >= $total_colors) {
|
if ($index >= $total_colors) {
|
||||||
|
|
||||||
\Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
||||||
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
||||||
$index = $index - $total_colors - 1;
|
$index = $index - $total_colors - 1;
|
||||||
|
|
||||||
|
@ -875,12 +878,15 @@ class Helper
|
||||||
$permission_name = $permission[$x]['permission'];
|
$permission_name = $permission[$x]['permission'];
|
||||||
|
|
||||||
if ($permission[$x]['display'] === true) {
|
if ($permission[$x]['display'] === true) {
|
||||||
if ($selected_arr) {
|
|
||||||
|
if (is_array($selected_arr)) {
|
||||||
|
|
||||||
if (array_key_exists($permission_name, $selected_arr)) {
|
if (array_key_exists($permission_name, $selected_arr)) {
|
||||||
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
|
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
|
||||||
} else {
|
} else {
|
||||||
$permissions_arr[$permission_name] = '0';
|
$permissions_arr[$permission_name] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$permissions_arr[$permission_name] = '0';
|
$permissions_arr[$permission_name] = '0';
|
||||||
}
|
}
|
||||||
|
@ -1012,7 +1018,7 @@ class Helper
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tmp_date = new \Carbon($date);
|
$tmp_date = new Carbon($date);
|
||||||
|
|
||||||
if ($type == 'datetime') {
|
if ($type == 'datetime') {
|
||||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||||
|
@ -1029,7 +1035,7 @@ class Helper
|
||||||
return $dt['formatted'];
|
return $dt['formatted'];
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::warning($e);
|
Log::warning($e);
|
||||||
return $date.' (Invalid '.$type.' value.)';
|
return $date.' (Invalid '.$type.' value.)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1342,7 +1348,7 @@ class Helper
|
||||||
public static function isDemoMode() {
|
public static function isDemoMode() {
|
||||||
if (config('app.lock_passwords') === true) {
|
if (config('app.lock_passwords') === true) {
|
||||||
return true;
|
return true;
|
||||||
\Log::debug('app locked!');
|
Log::debug('app locked!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1435,7 +1441,6 @@ class Helper
|
||||||
|
|
||||||
foreach (self::$language_map as $legacy => $new) {
|
foreach (self::$language_map as $legacy => $new) {
|
||||||
if ($language_code == $legacy) {
|
if ($language_code == $legacy) {
|
||||||
\Log::debug('Current language is '.$legacy.', using '.$new.' instead');
|
|
||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1446,6 +1451,7 @@ class Helper
|
||||||
|
|
||||||
public static function mapBackToLegacyLocale($new_locale = null)
|
public static function mapBackToLegacyLocale($new_locale = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (strlen($new_locale) <= 4) {
|
if (strlen($new_locale) <= 4) {
|
||||||
return $new_locale; //"new locale" apparently wasn't quite so new
|
return $new_locale; //"new locale" apparently wasn't quite so new
|
||||||
}
|
}
|
||||||
|
@ -1453,10 +1459,53 @@ class Helper
|
||||||
// This does a *reverse* search against our new language map array - given the value, find the *key* for it
|
// This does a *reverse* search against our new language map array - given the value, find the *key* for it
|
||||||
$legacy_locale = array_search($new_locale, self::$language_map);
|
$legacy_locale = array_search($new_locale, self::$language_map);
|
||||||
|
|
||||||
if($legacy_locale !== false) {
|
if ($legacy_locale !== false) {
|
||||||
return $legacy_locale;
|
return $legacy_locale;
|
||||||
}
|
}
|
||||||
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function determineLanguageDirection() {
|
||||||
|
return in_array(app()->getLocale(),
|
||||||
|
[
|
||||||
|
'ar-SA',
|
||||||
|
'fa-IR',
|
||||||
|
'he-IL'
|
||||||
|
]) ? 'rtl' : 'ltr';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static public function getRedirectOption($request, $id, $table, $asset_id = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
$redirect_option = Session::get('redirect_option');
|
||||||
|
$checkout_to_type = Session::get('checkout_to_type');
|
||||||
|
|
||||||
|
//return to index
|
||||||
|
if ($redirect_option == '0') {
|
||||||
|
switch ($table) {
|
||||||
|
case "Assets":
|
||||||
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return to thing being assigned
|
||||||
|
if ($redirect_option == '1') {
|
||||||
|
switch ($table) {
|
||||||
|
case "Assets":
|
||||||
|
return redirect()->route('hardware.show', $id ? $id : $asset_id)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return to thing being assigned to
|
||||||
|
if ($redirect_option == '2') {
|
||||||
|
switch ($checkout_to_type) {
|
||||||
|
case 'user':
|
||||||
|
return redirect()->route('users.show', $request->assigned_user)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
case 'location':
|
||||||
|
return redirect()->route('locations.show', $request->assigned_location)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
case 'asset':
|
||||||
|
return redirect()->route('hardware.show', $request->assigned_asset)->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,13 @@
|
||||||
namespace App\Helpers;
|
namespace App\Helpers;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
class StorageHelper
|
class StorageHelper
|
||||||
{
|
{
|
||||||
public static function downloader($filename, $disk = 'default')
|
public static function downloader($filename, $disk = 'default') : BinaryFileResponse | RedirectResponse | StreamedResponse
|
||||||
{
|
{
|
||||||
if ($disk == 'default') {
|
if ($disk == 'default') {
|
||||||
$disk = config('filesystems.default');
|
$disk = config('filesystems.default');
|
||||||
|
|
|
@ -7,10 +7,11 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Redirect;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/** This controller handles all actions related to Accessories for
|
/** This controller handles all actions related to Accessories for
|
||||||
* the Snipe-IT Asset Management application.
|
* the Snipe-IT Asset Management application.
|
||||||
|
@ -26,13 +27,10 @@ class AccessoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @see AccessoriesController::getDatatable() method that generates the JSON response
|
* @see AccessoriesController::getDatatable() method that generates the JSON response
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$this->authorize('index', Accessory::class);
|
$this->authorize('index', Accessory::class);
|
||||||
|
|
||||||
return view('accessories/index');
|
return view('accessories/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,10 +38,8 @@ class AccessoriesController extends Controller
|
||||||
* Returns a view with a form to create a new Accessory.
|
* Returns a view with a form to create a new Accessory.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create() : View
|
||||||
{
|
{
|
||||||
$this->authorize('create', Accessory::class);
|
$this->authorize('create', Accessory::class);
|
||||||
$category_type = 'accessory';
|
$category_type = 'accessory';
|
||||||
|
@ -57,10 +53,8 @@ class AccessoriesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize(Accessory::class);
|
$this->authorize(Accessory::class);
|
||||||
|
|
||||||
|
@ -79,7 +73,7 @@ class AccessoriesController extends Controller
|
||||||
$accessory->purchase_date = request('purchase_date');
|
$accessory->purchase_date = request('purchase_date');
|
||||||
$accessory->purchase_cost = request('purchase_cost');
|
$accessory->purchase_cost = request('purchase_cost');
|
||||||
$accessory->qty = request('qty');
|
$accessory->qty = request('qty');
|
||||||
$accessory->user_id = Auth::user()->id;
|
$accessory->user_id = auth()->id();
|
||||||
$accessory->supplier_id = request('supplier_id');
|
$accessory->supplier_id = request('supplier_id');
|
||||||
$accessory->notes = request('notes');
|
$accessory->notes = request('notes');
|
||||||
|
|
||||||
|
@ -99,15 +93,12 @@ class AccessoriesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit($accessoryId = null)
|
public function edit($accessoryId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($item = Accessory::find($accessoryId)) {
|
if ($item = Accessory::find($accessoryId)) {
|
||||||
$this->authorize($item);
|
$this->authorize($item);
|
||||||
|
|
||||||
return view('accessories/edit', compact('item'))->with('category_type', 'accessory');
|
return view('accessories/edit', compact('item'))->with('category_type', 'accessory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +112,8 @@ class AccessoriesController extends Controller
|
||||||
* @author [J. Vinsmoke]
|
* @author [J. Vinsmoke]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @since [v6.0]
|
* @since [v6.0]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function getClone($accessoryId = null)
|
public function getClone($accessoryId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('create', Accessory::class);
|
$this->authorize('create', Accessory::class);
|
||||||
|
@ -150,10 +140,8 @@ class AccessoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $accessoryId = null)
|
public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
|
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
|
||||||
|
|
||||||
|
@ -204,10 +192,8 @@ class AccessoriesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($accessoryId)
|
public function destroy($accessoryId) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($accessory = Accessory::find($accessoryId))) {
|
if (is_null($accessory = Accessory::find($accessoryId))) {
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
||||||
|
@ -224,7 +210,7 @@ class AccessoriesController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
|
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,10 +228,8 @@ class AccessoriesController extends Controller
|
||||||
* @param int $accessoryID
|
* @param int $accessoryID
|
||||||
* @see AccessoriesController::getDataView() method that generates the JSON response
|
* @see AccessoriesController::getDataView() method that generates the JSON response
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show($accessoryID = null)
|
public function show($accessoryID = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
|
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
|
||||||
$this->authorize('view', $accessory);
|
$this->authorize('view', $accessory);
|
||||||
|
|
|
@ -7,9 +7,13 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\UploadFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use Illuminate\Support\Facades\Response;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
class AccessoriesFilesController extends Controller
|
class AccessoriesFilesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -18,20 +22,17 @@ class AccessoriesFilesController extends Controller
|
||||||
*
|
*
|
||||||
* @param UploadFileRequest $request
|
* @param UploadFileRequest $request
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*@author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(UploadFileRequest $request, $accessoryId = null)
|
public function store(UploadFileRequest $request, $accessoryId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
return redirect()->route('accessories.show', ['accessory'=>$accessoryId])->with('error', trans('general.feature_disabled'));
|
return redirect()->route('accessories.show', ['accessory'=>$accessoryId])->with('error', trans('general.feature_disabled'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$accessory = Accessory::find($accessoryId);
|
$accessory = Accessory::find($accessoryId);
|
||||||
|
|
||||||
if (isset($accessory->id)) {
|
if (isset($accessory->id)) {
|
||||||
|
@ -68,10 +69,8 @@ class AccessoriesFilesController extends Controller
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($accessoryId = null, $fileId = null)
|
public function destroy($accessoryId = null, $fileId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
$accessory = Accessory::find($accessoryId);
|
$accessory = Accessory::find($accessoryId);
|
||||||
|
|
||||||
|
@ -85,7 +84,7 @@ class AccessoriesFilesController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::delete('accessories/'.$log->filename);
|
Storage::delete('accessories/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,13 +105,11 @@ class AccessoriesFilesController extends Controller
|
||||||
* @since [v1.4]
|
* @since [v1.4]
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @return \Symfony\Accessory\HttpFoundation\Response
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show($accessoryId = null, $fileId = null, $download = true)
|
public function show($accessoryId = null, $fileId = null, $download = true) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||||
$accessory = Accessory::find($accessoryId);
|
$accessory = Accessory::find($accessoryId);
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,8 +126,8 @@ class AccessoriesFilesController extends Controller
|
||||||
$file = 'private_uploads/accessories/'.$log->filename;
|
$file = 'private_uploads/accessories/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|
|
@ -7,8 +7,9 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class AccessoryCheckinController extends Controller
|
class AccessoryCheckinController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -19,15 +20,10 @@ class AccessoryCheckinController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryUserId
|
* @param int $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return View
|
|
||||||
* @internal param int $accessoryId
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create($accessoryUserId = null, $backto = null)
|
public function create($accessoryUserId = null, $backto = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
||||||
// Redirect to the accessory management page with error
|
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,15 +40,10 @@ class AccessoryCheckinController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param null $accessoryUserId
|
* @param null $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @internal param int $accessoryId
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $accessoryUserId = null, $backto = null)
|
public function store(Request $request, $accessoryUserId = null, $backto = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
||||||
// Redirect to the accessory management page with error
|
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +61,7 @@ class AccessoryCheckinController extends Controller
|
||||||
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
|
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
|
||||||
$return_to = e($accessory_user->assigned_to);
|
$return_to = e($accessory_user->assigned_to);
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($accessory, User::find($return_to), Auth::user(), $request->input('note'), $checkin_at));
|
event(new CheckoutableCheckedIn($accessory, User::find($return_to), auth()->user(), $request->input('note'), $checkin_at));
|
||||||
|
|
||||||
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
|
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,14 @@ namespace App\Http\Controllers\Accessories;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\AccessoryCheckoutRequest;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use \Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Support\Facades\Input;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class AccessoryCheckoutController extends Controller
|
class AccessoryCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -19,10 +20,8 @@ class AccessoryCheckoutController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create($id)
|
public function create($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($accessory = Accessory::withCount('users as users_count')->find($id)) {
|
if ($accessory = Accessory::withCount('users as users_count')->find($id)) {
|
||||||
|
@ -58,46 +57,29 @@ class AccessoryCheckoutController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryId
|
* @param int $accessory
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $accessoryId)
|
public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
|
||||||
// Redirect to the accessory management page with error
|
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.user_not_found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
$accessory->assigned_to = $request->input('assigned_to');
|
||||||
|
$user = User::find($request->input('assigned_to'));
|
||||||
|
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||||
|
|
||||||
if (!$user = User::find($request->input('assigned_to'))) {
|
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||||
return redirect()->route('accessories.checkout.show', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
|
$accessory->users()->attach($accessory->id, [
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'assigned_to' => $request->input('assigned_to'),
|
||||||
|
'note' => $request->input('note'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
|
||||||
// Make sure there is at least one available to checkout
|
|
||||||
if ($accessory->numRemaining() <= 0){
|
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Update the accessory data
|
|
||||||
$accessory->assigned_to = e($request->input('assigned_to'));
|
|
||||||
|
|
||||||
$accessory->users()->attach($accessory->id, [
|
|
||||||
'accessory_id' => $accessory->id,
|
|
||||||
'created_at' => Carbon::now(),
|
|
||||||
'user_id' => Auth::id(),
|
|
||||||
'assigned_to' => $request->get('assigned_to'),
|
|
||||||
'note' => $request->input('note'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
|
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
|
|
||||||
|
|
||||||
// Redirect to the new accessory page
|
// Redirect to the new accessory page
|
||||||
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success'));
|
return redirect()->route('accessories.index')
|
||||||
|
->with('success', trans('admin/accessories/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,25 +23,23 @@ use App\Notifications\AcceptanceAssetAcceptedNotification;
|
||||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Http\Controllers\SettingsController;
|
use App\Http\Controllers\SettingsController;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use phpDocumentor\Reflection\Types\Compound;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class AcceptanceController extends Controller
|
class AcceptanceController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Show a listing of pending checkout acceptances for the current user
|
* Show a listing of pending checkout acceptances for the current user
|
||||||
*
|
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$acceptances = CheckoutAcceptance::forUser(Auth::user())->pending()->get();
|
$acceptances = CheckoutAcceptance::forUser(auth()->user())->pending()->get();
|
||||||
|
|
||||||
return view('account/accept.index', compact('acceptances'));
|
return view('account/accept.index', compact('acceptances'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,9 +47,8 @@ class AcceptanceController extends Controller
|
||||||
* Shows a form to either accept or decline the checkout acceptance
|
* Shows a form to either accept or decline the checkout acceptance
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function create($id)
|
public function create($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$acceptance = CheckoutAcceptance::find($id);
|
$acceptance = CheckoutAcceptance::find($id);
|
||||||
|
|
||||||
|
@ -64,7 +61,7 @@ class AcceptanceController extends Controller
|
||||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $acceptance->isCheckedOutTo(Auth::user())) {
|
if (! $acceptance->isCheckedOutTo(auth()->user())) {
|
||||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +77,8 @@ class AcceptanceController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $id)
|
public function store(Request $request, $id) : RedirectResponse
|
||||||
{
|
{
|
||||||
$acceptance = CheckoutAcceptance::find($id);
|
$acceptance = CheckoutAcceptance::find($id);
|
||||||
|
|
||||||
|
@ -94,7 +90,7 @@ class AcceptanceController extends Controller
|
||||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $acceptance->isCheckedOutTo(Auth::user())) {
|
if (! $acceptance->isCheckedOutTo(auth()->user())) {
|
||||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +219,7 @@ class AcceptanceController extends Controller
|
||||||
'item_model' => $display_model,
|
'item_model' => $display_model,
|
||||||
'item_serial' => $item->serial,
|
'item_serial' => $item->serial,
|
||||||
'eula' => $item->getEula(),
|
'eula' => $item->getEula(),
|
||||||
|
'note' => $request->input('note'),
|
||||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
||||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
||||||
'assigned_to' => $assigned_to,
|
'assigned_to' => $assigned_to,
|
||||||
|
@ -233,12 +230,12 @@ class AcceptanceController extends Controller
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
if ($pdf_view_route!='') {
|
||||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||||
}
|
}
|
||||||
|
|
||||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename);
|
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||||
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
|
||||||
event(new CheckoutAccepted($acceptance));
|
event(new CheckoutAccepted($acceptance));
|
||||||
|
|
||||||
|
@ -306,10 +303,12 @@ class AcceptanceController extends Controller
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'item_tag' => $item->asset_tag,
|
'item_tag' => $item->asset_tag,
|
||||||
'item_model' => $display_model,
|
'item_model' => $display_model,
|
||||||
'item_serial' => $item->serial,
|
'item_serial' => $item->serial,
|
||||||
|
'note' => $request->input('note'),
|
||||||
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
|
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
|
||||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||||
'assigned_to' => $assigned_to,
|
'assigned_to' => $assigned_to,
|
||||||
|
@ -318,12 +317,12 @@ class AcceptanceController extends Controller
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
if ($pdf_view_route!='') {
|
||||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||||
}
|
}
|
||||||
|
|
||||||
$acceptance->decline($sig_filename);
|
$acceptance->decline($sig_filename, $request->input('note'));
|
||||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||||
event(new CheckoutDeclined($acceptance));
|
event(new CheckoutDeclined($acceptance));
|
||||||
$return_msg = trans('admin/users/message.declined');
|
$return_msg = trans('admin/users/message.declined');
|
||||||
|
|
|
@ -3,34 +3,44 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Actionlog;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Response;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use \Illuminate\Http\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
class ActionlogController extends Controller
|
class ActionlogController extends Controller
|
||||||
{
|
{
|
||||||
public function displaySig($filename)
|
public function displaySig($filename) : RedirectResponse | Response | bool
|
||||||
{
|
{
|
||||||
// PHP doesn't let you handle file not found errors well with
|
// PHP doesn't let you handle file not found errors well with
|
||||||
// file_get_contents, so we set the error reporting for just this class
|
// file_get_contents, so we set the error reporting for just this class
|
||||||
error_reporting(0);
|
error_reporting(0);
|
||||||
|
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
$disk = config('filesystems.default');
|
||||||
$file = config('app.private_uploads').'/signatures/'.$filename;
|
switch (config("filesystems.disks.$disk.driver")) {
|
||||||
$filetype = Helper::checkUploadIsImage($file);
|
|
||||||
|
|
||||||
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
|
case 's3':
|
||||||
if ($contents === false) {
|
$file = 'private_uploads/signatures/'.$filename;
|
||||||
\Log::warn('File '.$file.' not found');
|
return redirect()->away(Storage::disk($disk)->temporaryUrl($file, now()->addMinutes(5)));
|
||||||
return false;
|
default:
|
||||||
} else {
|
$this->authorize('view', \App\Models\Asset::class);
|
||||||
return Response::make($contents)->header('Content-Type', $filetype);
|
$file = config('app.private_uploads').'/signatures/'.$filename;
|
||||||
|
$filetype = Helper::checkUploadIsImage($file);
|
||||||
|
|
||||||
|
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
|
||||||
|
if ($contents === false) {
|
||||||
|
Log::warning('File '.$file.' not found');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return response()->make($contents)->header('Content-Type', $filetype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public function getStoredEula($filename){
|
|
||||||
|
public function getStoredEula($filename) : Response | BinaryFileResponse
|
||||||
|
{
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
$this->authorize('view', \App\Models\Asset::class);
|
||||||
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
||||||
|
return response()->download($file);
|
||||||
return Response::download($file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,20 @@ namespace App\Http\Controllers\Api;
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\AccessoryCheckoutRequest;
|
||||||
|
use App\Http\Requests\StoreAccessoryRequest;
|
||||||
use App\Http\Transformers\AccessoriesTransformer;
|
use App\Http\Transformers\AccessoriesTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
|
||||||
|
|
||||||
class AccessoriesController extends Controller
|
class AccessoriesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -120,12 +123,12 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreAccessoryRequest $request)
|
||||||
{
|
{
|
||||||
$this->authorize('create', Accessory::class);
|
$this->authorize('create', Accessory::class);
|
||||||
$accessory = new Accessory;
|
$accessory = new Accessory;
|
||||||
|
@ -143,10 +146,10 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return array
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
|
@ -160,10 +163,10 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return array
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function accessory_detail($id)
|
public function accessory_detail($id)
|
||||||
{
|
{
|
||||||
|
@ -272,43 +275,31 @@ class AccessoriesController extends Controller
|
||||||
* If Slack is enabled and/or asset acceptance is enabled, it will also
|
* If Slack is enabled and/or asset acceptance is enabled, it will also
|
||||||
* trigger a Slack message and send an email.
|
* trigger a Slack message and send an email.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function checkout(Request $request, $accessoryId)
|
public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory)
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
$accessory->assigned_to = $request->input('assigned_to');
|
||||||
|
$user = User::find($request->input('assigned_to'));
|
||||||
|
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||||
if ($accessory->numRemaining() > 0) {
|
|
||||||
|
|
||||||
if (! $user = User::find($request->input('assigned_to'))) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkout.user_does_not_exist')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the accessory data
|
|
||||||
$accessory->assigned_to = $request->input('assigned_to');
|
|
||||||
|
|
||||||
$accessory->users()->attach($accessory->id, [
|
$accessory->users()->attach($accessory->id, [
|
||||||
'accessory_id' => $accessory->id,
|
'accessory_id' => $accessory->id,
|
||||||
'created_at' => Carbon::now(),
|
'created_at' => Carbon::now(),
|
||||||
'user_id' => Auth::id(),
|
'user_id' => Auth::id(),
|
||||||
'assigned_to' => $request->get('assigned_to'),
|
'assigned_to' => $request->input('assigned_to'),
|
||||||
'note' => $request->get('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No accessories remaining'));
|
// Set this value to be able to pass the qty through to the event
|
||||||
|
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +311,7 @@ class AccessoriesController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryUserId
|
* @param int $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @internal param int $accessoryId
|
* @internal param int $accessoryId
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $accessoryUserId = null)
|
public function checkin(Request $request, $accessoryUserId = null)
|
||||||
|
|
200
app/Http/Controllers/Api/AssetFilesController.php
Normal file
200
app/Http/Controllers/Api/AssetFilesController.php
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Helpers\StorageHelper;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use App\Http\Requests\UploadFileRequest;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class controls file related actions related
|
||||||
|
* to assets for the Snipe-IT Asset Management application.
|
||||||
|
*
|
||||||
|
* Based on the Assets/AssetFilesController by A. Gianotto <snipe@snipe.net>
|
||||||
|
*
|
||||||
|
* @version v1.0
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
class AssetFilesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Accepts a POST to upload a file to the server.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\UploadFileRequest $request
|
||||||
|
* @param int $assetId
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function store(UploadFileRequest $request, $assetId = null) : JsonResponse
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we are allowed to update this asset
|
||||||
|
$this->authorize('update', $asset);
|
||||||
|
|
||||||
|
if ($request->hasFile('file')) {
|
||||||
|
// If the file storage directory doesn't exist; create it
|
||||||
|
if (! Storage::exists('private_uploads/assets')) {
|
||||||
|
Storage::makeDirectory('private_uploads/assets', 775);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over the attached files and add them to the asset
|
||||||
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||||
|
|
||||||
|
$asset->logUpload($file_name, e($request->get('notes')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done - report success
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only reach here if no files were included in the POST, so tell the user this
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.upload.nofiles')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the files for an asset.
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function list($assetId = null) : JsonResponse
|
||||||
|
{
|
||||||
|
// Start by checking if the asset being acted upon exists
|
||||||
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the asset is valid
|
||||||
|
if (isset($asset->id)) {
|
||||||
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
|
// Check that there are some uploads on this asset that can be listed
|
||||||
|
if ($asset->uploads->count() > 0) {
|
||||||
|
$files = array();
|
||||||
|
foreach ($asset->uploads as $upload) {
|
||||||
|
array_push($files, $upload);
|
||||||
|
}
|
||||||
|
// Give the list of files back to the user
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $files, trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are no files.
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', array(), trans('admin/hardware/message.upload.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back an error message
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for permissions and display the file.
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @param int $fileId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function show($assetId = null, $fileId = null) : 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)) {
|
||||||
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
|
// Check that the file being requested exists for the asset
|
||||||
|
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.no_match', ['id' => $fileId])), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form the full filename with path
|
||||||
|
$file = 'private_uploads/assets/'.$log->filename;
|
||||||
|
Log::debug('Checking for '.$file);
|
||||||
|
|
||||||
|
if ($log->action_type == 'audit') {
|
||||||
|
$file = 'private_uploads/audits/'.$log->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the file actually exists on the filesystem
|
||||||
|
if (! Storage::exists($file)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.does_not_exist', ['id' => $fileId])), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request('inline') == 'true') {
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Content-Disposition' => 'inline',
|
||||||
|
];
|
||||||
|
|
||||||
|
return Storage::download($file, $log->filename, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StorageHelper::downloader($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back an error message
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.error', ['id' => $fileId])), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the associated file
|
||||||
|
*
|
||||||
|
* @param int $assetId
|
||||||
|
* @param int $fileId
|
||||||
|
* @since [v6.0]
|
||||||
|
* @author [T. Scarsbrook] [<snipe@scarzybrook.co.uk>]
|
||||||
|
*/
|
||||||
|
public function destroy($assetId = null, $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';
|
||||||
|
|
||||||
|
// the asset is valid
|
||||||
|
if (isset($asset->id)) {
|
||||||
|
$this->authorize('update', $asset);
|
||||||
|
|
||||||
|
// Check for the file
|
||||||
|
$log = Actionlog::find($fileId);
|
||||||
|
if ($log) {
|
||||||
|
// Check the file actually exists, and delete it
|
||||||
|
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||||
|
Storage::delete($rel_path.'/'.$log->filename);
|
||||||
|
}
|
||||||
|
// Delete the record of the file
|
||||||
|
$log->delete();
|
||||||
|
|
||||||
|
// All deleting done - notify the user of success
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.deletefile.success')), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The file doesn't seem to really exist, so report an error
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,10 +8,9 @@ use App\Http\Transformers\AssetMaintenancesTransformer;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetMaintenance;
|
use App\Models\AssetMaintenance;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Asset Maintenance for
|
* This controller handles all actions related to Asset Maintenance for
|
||||||
|
@ -22,7 +21,6 @@ use Illuminate\Support\Facades\Input;
|
||||||
class AssetMaintenancesController extends Controller
|
class AssetMaintenancesController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the JSON response for asset maintenances listing view.
|
* Generates the JSON response for asset maintenances listing view.
|
||||||
*
|
*
|
||||||
|
@ -30,9 +28,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
|
@ -120,9 +117,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// create a new model instance
|
// create a new model instance
|
||||||
|
@ -148,9 +144,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $request
|
* @param int $request
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
|
|
||||||
|
@ -186,9 +181,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function destroy($assetMaintenanceId)
|
public function destroy($assetMaintenanceId) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
|
@ -212,9 +206,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function show($assetMaintenanceId)
|
public function show($assetMaintenanceId) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||||
|
|
|
@ -4,14 +4,16 @@ namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\StoreAssetModelRequest;
|
||||||
use App\Http\Transformers\AssetModelsTransformer;
|
use App\Http\Transformers\AssetModelsTransformer;
|
||||||
use App\Http\Transformers\AssetsTransformer;
|
use App\Http\Transformers\AssetsTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to asset models for
|
* This class controls all actions related to asset models for
|
||||||
|
@ -27,9 +29,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', AssetModel::class);
|
$this->authorize('view', AssetModel::class);
|
||||||
$allowed_columns =
|
$allowed_columns =
|
||||||
|
@ -115,10 +116,9 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\StoreAssetModelRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreAssetModelRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', AssetModel::class);
|
$this->authorize('create', AssetModel::class);
|
||||||
$assetmodel = new AssetModel;
|
$assetmodel = new AssetModel;
|
||||||
|
@ -139,9 +139,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', AssetModel::class);
|
$this->authorize('view', AssetModel::class);
|
||||||
$assetmodel = AssetModel::withCount('assets as assets_count')->findOrFail($id);
|
$assetmodel = AssetModel::withCount('assets as assets_count')->findOrFail($id);
|
||||||
|
@ -155,9 +154,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function assets($id)
|
public function assets($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', AssetModel::class);
|
$this->authorize('view', AssetModel::class);
|
||||||
$assets = Asset::where('model_id', '=', $id)->get();
|
$assets = Asset::where('model_id', '=', $id)->get();
|
||||||
|
@ -175,7 +173,7 @@ class AssetModelsController extends Controller
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(StoreAssetModelRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', AssetModel::class);
|
$this->authorize('update', AssetModel::class);
|
||||||
$assetmodel = AssetModel::findOrFail($id);
|
$assetmodel = AssetModel::findOrFail($id);
|
||||||
|
@ -208,9 +206,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', AssetModel::class);
|
$this->authorize('delete', AssetModel::class);
|
||||||
$assetmodel = AssetModel::findOrFail($id);
|
$assetmodel = AssetModel::findOrFail($id);
|
||||||
|
@ -224,7 +221,7 @@ class AssetModelsController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('assetmodels/'.$assetmodel->image);
|
Storage::disk('public')->delete('assetmodels/'.$assetmodel->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::info($e);
|
Log::info($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +237,7 @@ class AssetModelsController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
|
|
|
@ -25,19 +25,13 @@ use App\Models\License;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use \Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Input;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Paginator;
|
|
||||||
use Slack;
|
|
||||||
use Str;
|
|
||||||
use TCPDF;
|
|
||||||
use Validator;
|
|
||||||
use Route;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,9 +51,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request, $audit = null)
|
public function index(Request $request, $action = null, $upcoming_status = null) : JsonResponse | array
|
||||||
{
|
{
|
||||||
|
|
||||||
$filter_non_deprecable_assets = false;
|
$filter_non_deprecable_assets = false;
|
||||||
|
@ -155,17 +148,44 @@ class AssetsController extends Controller
|
||||||
$assets->TextSearch($request->input('search'));
|
$assets->TextSearch($request->input('search'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used by the audit reporting routes
|
|
||||||
if (Gate::allows('audit', Asset::class)) {
|
/**
|
||||||
switch ($audit) {
|
* Handle due and overdue audits and checkin dates
|
||||||
case 'due':
|
*/
|
||||||
$assets->DueOrOverdueForAudit($settings);
|
switch ($action) {
|
||||||
break;
|
case 'audits':
|
||||||
case 'overdue':
|
|
||||||
$assets->overdueForAudit($settings);
|
switch ($upcoming_status) {
|
||||||
break;
|
case 'due':
|
||||||
|
$assets->DueForAudit($settings);
|
||||||
|
break;
|
||||||
|
case 'overdue':
|
||||||
|
$assets->OverdueForAudit();
|
||||||
|
break;
|
||||||
|
case 'due-or-overdue':
|
||||||
|
$assets->DueOrOverdueForAudit($settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'checkins':
|
||||||
|
switch ($upcoming_status) {
|
||||||
|
case 'due':
|
||||||
|
$assets->DueForCheckin($settings);
|
||||||
|
break;
|
||||||
|
case 'overdue':
|
||||||
|
$assets->OverdueForCheckin();
|
||||||
|
break;
|
||||||
|
case 'due-or-overdue':
|
||||||
|
$assets->DueOrOverdueForCheckin($settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* End handling due and overdue audits and checkin dates
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// This is used by the sidenav, mostly
|
// This is used by the sidenav, mostly
|
||||||
|
@ -389,9 +409,8 @@ class AssetsController extends Controller
|
||||||
* @param string $tag
|
* @param string $tag
|
||||||
* @since [v4.2.1]
|
* @since [v4.2.1]
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function showByTag(Request $request, $tag)
|
public function showByTag(Request $request, $tag) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('index', Asset::class);
|
$this->authorize('index', Asset::class);
|
||||||
$assets = Asset::where('asset_tag', $tag)->with('assetstatus')->with('assignedTo');
|
$assets = Asset::where('asset_tag', $tag)->with('assetstatus')->with('assignedTo');
|
||||||
|
@ -429,7 +448,7 @@ class AssetsController extends Controller
|
||||||
* @since [v4.2.1]
|
* @since [v4.2.1]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function showBySerial(Request $request, $serial)
|
public function showBySerial(Request $request, $serial) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('index', Asset::class);
|
$this->authorize('index', Asset::class);
|
||||||
$assets = Asset::where('serial', $serial)->with('assetstatus')->with('assignedTo');
|
$assets = Asset::where('serial', $serial)->with('assetstatus')->with('assignedTo');
|
||||||
|
@ -456,19 +475,20 @@ class AssetsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function show(Request $request, $id)
|
public function show(Request $request, $id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()
|
if ($asset = Asset::with('assetstatus')
|
||||||
->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')->findOrFail($id)) {
|
->with('assignedTo')->withTrashed()
|
||||||
|
->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')->find($id)) {
|
||||||
$this->authorize('view', $asset);
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
return (new AssetsTransformer)->transformAsset($asset, $request->input('components') );
|
return (new AssetsTransformer)->transformAsset($asset, $request->input('components') );
|
||||||
}
|
}
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function licenses(Request $request, $id)
|
public function licenses(Request $request, $id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
@ -485,9 +505,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$assets = Asset::select([
|
$assets = Asset::select([
|
||||||
|
@ -612,7 +631,7 @@ class AssetsController extends Controller
|
||||||
$target = Location::find(request('assigned_location'));
|
$target = Location::find(request('assigned_location'));
|
||||||
}
|
}
|
||||||
if (isset($target)) {
|
if (isset($target)) {
|
||||||
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')));
|
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->image) {
|
if ($asset->image) {
|
||||||
|
@ -634,9 +653,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
|
|
||||||
|
@ -665,25 +683,26 @@ class AssetsController extends Controller
|
||||||
$model = AssetModel::find($asset->model_id);
|
$model = AssetModel::find($asset->model_id);
|
||||||
|
|
||||||
// Update custom fields
|
// Update custom fields
|
||||||
|
$problems_updating_encrypted_custom_fields = false;
|
||||||
if (($model) && (isset($model->fieldset))) {
|
if (($model) && (isset($model->fieldset))) {
|
||||||
foreach ($model->fieldset->fields as $field) {
|
foreach ($model->fieldset->fields as $field) {
|
||||||
$field_val = $request->input($field->db_column, null);
|
$field_val = $request->input($field->db_column, null);
|
||||||
|
|
||||||
if ($request->has($field->db_column)) {
|
if ($request->has($field->db_column)) {
|
||||||
if ($field->field_encrypted == '1') {
|
|
||||||
if (Gate::allows('admin')) {
|
|
||||||
$asset->{$field->db_column} = Crypt::encrypt($field_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($field->element == 'checkbox') {
|
if ($field->element == 'checkbox') {
|
||||||
if(is_array($field_val)) {
|
if(is_array($field_val)) {
|
||||||
$field_val = implode(',', $field_val);
|
$field_val = implode(',', $field_val);
|
||||||
$asset->{$field->db_column} = $field_val;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
if ($field->field_encrypted == '1') {
|
||||||
$asset->{$field->db_column} = $field_val;
|
if (Gate::allows('admin')) {
|
||||||
|
$field_val = Crypt::encrypt($field_val);
|
||||||
|
} else {
|
||||||
|
$problems_updating_encrypted_custom_fields = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
$asset->{$field->db_column} = $field_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,15 +721,18 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($target)) {
|
if (isset($target)) {
|
||||||
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
|
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->image) {
|
if ($asset->image) {
|
||||||
$asset->image = $asset->getImageUrl();
|
$asset->image = $asset->getImageUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
if ($problems_updating_encrypted_custom_fields) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||||
|
} else {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
|
@ -726,9 +748,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Asset::class);
|
$this->authorize('delete', Asset::class);
|
||||||
|
|
||||||
|
@ -755,9 +776,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v5.1.18]
|
* @since [v5.1.18]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function restore(Request $request, $assetId = null)
|
public function restore(Request $request, $assetId = null) : JsonResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($asset = Asset::withTrashed()->find($assetId)) {
|
if ($asset = Asset::withTrashed()->find($assetId)) {
|
||||||
|
@ -785,9 +805,8 @@ class AssetsController extends Controller
|
||||||
* @author [N. Butler]
|
* @author [N. Butler]
|
||||||
* @param string $tag
|
* @param string $tag
|
||||||
* @since [v6.0.5]
|
* @since [v6.0.5]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function checkoutByTag(AssetCheckoutRequest $request, $tag)
|
public function checkoutByTag(AssetCheckoutRequest $request, $tag) : JsonResponse
|
||||||
{
|
{
|
||||||
if ($asset = Asset::where('asset_tag', $tag)->first()) {
|
if ($asset = Asset::where('asset_tag', $tag)->first()) {
|
||||||
return $this->checkout($request, $asset->id);
|
return $this->checkout($request, $asset->id);
|
||||||
|
@ -801,9 +820,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function checkout(AssetCheckoutRequest $request, $asset_id)
|
public function checkout(AssetCheckoutRequest $request, $asset_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('checkout', Asset::class);
|
$this->authorize('checkout', Asset::class);
|
||||||
$asset = Asset::findOrFail($asset_id);
|
$asset = Asset::findOrFail($asset_id);
|
||||||
|
@ -820,7 +838,6 @@ class AssetsController extends Controller
|
||||||
'asset_tag' => $asset->asset_tag,
|
'asset_tag' => $asset->asset_tag,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// This item is checked out to a location
|
// This item is checked out to a location
|
||||||
if (request('checkout_to_type') == 'location') {
|
if (request('checkout_to_type') == 'location') {
|
||||||
$target = Location::find(request('assigned_location'));
|
$target = Location::find(request('assigned_location'));
|
||||||
|
@ -847,13 +864,10 @@ class AssetsController extends Controller
|
||||||
$asset->status_id = $request->get('status_id');
|
$asset->status_id = $request->get('status_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (! isset($target)) {
|
if (! isset($target)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset '.e($asset->asset_tag).' is invalid - '.$error_payload['target_type'].' does not exist.'));
|
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset '.e($asset->asset_tag).' is invalid - '.$error_payload['target_type'].' does not exist.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
|
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
|
||||||
$expected_checkin = request('expected_checkin', null);
|
$expected_checkin = request('expected_checkin', null);
|
||||||
$note = request('note', null);
|
$note = request('note', null);
|
||||||
|
@ -869,9 +883,7 @@ class AssetsController extends Controller
|
||||||
// $asset->location_id = $target->rtd_location_id;
|
// $asset->location_id = $target->rtd_location_id;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if ($asset->checkOut($target, auth()->user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id)) {
|
||||||
|
|
||||||
if ($asset->checkOut($target, Auth::user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,9 +897,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $asset_id)
|
public function checkin(Request $request, $asset_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$asset = Asset::with('model')->findOrFail($asset_id);
|
$asset = Asset::with('model')->findOrFail($asset_id);
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
@ -952,7 +963,7 @@ class AssetsController extends Controller
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', [
|
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||||
'asset_tag'=> e($asset->asset_tag),
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
@ -969,9 +980,8 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Janes] [<ajanes@adagiohealth.org>]
|
* @author [A. Janes] [<ajanes@adagiohealth.org>]
|
||||||
* @since [v6.0]
|
* @since [v6.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function checkinByTag(Request $request, $tag = null)
|
public function checkinByTag(Request $request, $tag = null) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('checkin', Asset::class);
|
$this->authorize('checkin', Asset::class);
|
||||||
if(null == $tag && null !== ($request->input('asset_tag'))) {
|
if(null == $tag && null !== ($request->input('asset_tag'))) {
|
||||||
|
@ -995,31 +1005,44 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function audit(Request $request)
|
public function audit(Request $request) : JsonResponse
|
||||||
|
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('audit', Asset::class);
|
||||||
$rules = [
|
|
||||||
'asset_tag' => 'required',
|
|
||||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
|
||||||
'next_audit_date' => 'date|nullable',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||||
|
|
||||||
|
// No tag passed - return an error
|
||||||
|
if (!$request->filled('asset_tag')) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> '',
|
||||||
|
'error'=> trans('admin/hardware/message.no_tag'),
|
||||||
|
], trans('admin/hardware/message.no_tag')), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
|
$asset = Asset::where('asset_tag', '=', $request->input('asset_tag'))->first();
|
||||||
|
|
||||||
|
|
||||||
if ($asset) {
|
if ($asset) {
|
||||||
// We don't want to log this as a normal update, so let's bypass that
|
|
||||||
|
/**
|
||||||
|
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
|
||||||
|
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
|
||||||
|
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
|
||||||
|
* the audit log entry we're creating through this controller.
|
||||||
|
*
|
||||||
|
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
|
||||||
|
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
|
||||||
|
* will bypass normal model-level validation that's usually handled at the observer )
|
||||||
|
*
|
||||||
|
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
|
||||||
|
* which manually invokes Watson Validating to make sure the asset's model is valid.
|
||||||
|
*
|
||||||
|
* @see \App\Observers\AssetObserver::updating()
|
||||||
|
*/
|
||||||
$asset->unsetEventDispatcher();
|
$asset->unsetEventDispatcher();
|
||||||
$asset->next_audit_date = $dt;
|
$asset->next_audit_date = $dt;
|
||||||
|
|
||||||
|
@ -1035,8 +1058,12 @@ class AssetsController extends Controller
|
||||||
|
|
||||||
$asset->last_audit_date = date('Y-m-d H:i:s');
|
$asset->last_audit_date = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
if ($asset->save()) {
|
/**
|
||||||
$log = $asset->logAudit(request('note'), request('location_id'));
|
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
|
||||||
|
* We have to invoke this manually because of the unsetEventDispatcher() above.)
|
||||||
|
*/
|
||||||
|
if ($asset->isValid() && $asset->save()) {
|
||||||
|
$asset->logAudit(request('note'), request('location_id'));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', [
|
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||||
'asset_tag'=> e($asset->asset_tag),
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
@ -1044,9 +1071,23 @@ class AssetsController extends Controller
|
||||||
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
|
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
|
||||||
], trans('admin/hardware/message.audit.success')));
|
], trans('admin/hardware/message.audit.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asset failed validation or was not able to be saved
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
'error'=> $asset->getErrors()->first(),
|
||||||
|
], trans('admin/hardware/message.audit.error', ['error' => $asset->getErrors()->first()])), 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.e($request->input('asset_tag')).' not found'));
|
|
||||||
|
// No matching asset for the asset tag that was passed.
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> e($request->input('asset_tag')),
|
||||||
|
'error'=> trans('admin/hardware/message.audit.error'),
|
||||||
|
], trans('admin/hardware/message.audit.error', ['error' => trans('admin/hardware/message.does_not_exist')])), 200);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1056,9 +1097,8 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function requestable(Request $request)
|
public function requestable(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('viewRequestable', Asset::class);
|
$this->authorize('viewRequestable', Asset::class);
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ use App\Http\Transformers\CategoriesTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
|
|
||||||
class CategoriesController extends Controller
|
class CategoriesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@ class CategoriesController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Category::class);
|
$this->authorize('view', Category::class);
|
||||||
$allowed_columns = [
|
$allowed_columns = [
|
||||||
|
@ -115,7 +115,7 @@ class CategoriesController extends Controller
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Category::class);
|
$this->authorize('create', Category::class);
|
||||||
$category = new Category;
|
$category = new Category;
|
||||||
|
@ -136,9 +136,8 @@ class CategoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Category::class);
|
$this->authorize('view', Category::class);
|
||||||
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
||||||
|
@ -156,7 +155,7 @@ class CategoriesController extends Controller
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Category::class);
|
$this->authorize('update', Category::class);
|
||||||
$category = Category::findOrFail($id);
|
$category = Category::findOrFail($id);
|
||||||
|
@ -164,7 +163,7 @@ class CategoriesController extends Controller
|
||||||
// Don't allow the user to change the category_type once it's been created
|
// Don't allow the user to change the category_type once it's been created
|
||||||
if (($request->filled('category_type')) && ($category->category_type != $request->input('category_type'))) {
|
if (($request->filled('category_type')) && ($category->category_type != $request->input('category_type'))) {
|
||||||
return response()->json(
|
return response()->json(
|
||||||
Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.update.cannot_change_category_type'))
|
Helper::formatStandardApiResponse('error', null, ['category_type' => trans('admin/categories/message.update.cannot_change_category_type')], 422)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$category->fill($request->all());
|
$category->fill($request->all());
|
||||||
|
@ -185,7 +184,7 @@ class CategoriesController extends Controller
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Category::class);
|
$this->authorize('delete', Category::class);
|
||||||
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
||||||
|
@ -208,7 +207,7 @@ class CategoriesController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request, $category_type = 'asset')
|
public function selectlist(Request $request, $category_type = 'asset') : array
|
||||||
{
|
{
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
$categories = Category::select([
|
$categories = Category::select([
|
||||||
|
|
|
@ -10,6 +10,7 @@ use App\Models\Company;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class CompaniesController extends Controller
|
class CompaniesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -18,9 +19,8 @@ class CompaniesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Company::class);
|
$this->authorize('view', Company::class);
|
||||||
|
|
||||||
|
@ -79,9 +79,8 @@ class CompaniesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Company::class);
|
$this->authorize('create', Company::class);
|
||||||
$company = new Company;
|
$company = new Company;
|
||||||
|
@ -102,9 +101,8 @@ class CompaniesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Company::class);
|
$this->authorize('view', Company::class);
|
||||||
$company = Company::findOrFail($id);
|
$company = Company::findOrFail($id);
|
||||||
|
@ -120,9 +118,8 @@ class CompaniesController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Company::class);
|
$this->authorize('update', Company::class);
|
||||||
$company = Company::findOrFail($id);
|
$company = Company::findOrFail($id);
|
||||||
|
@ -144,9 +141,8 @@ class CompaniesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Company::class);
|
$this->authorize('delete', Company::class);
|
||||||
$company = Company::findOrFail($id);
|
$company = Company::findOrFail($id);
|
||||||
|
@ -169,7 +165,7 @@ class CompaniesController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
$companies = Company::select([
|
$companies = Company::select([
|
||||||
|
|
|
@ -5,15 +5,17 @@ namespace App\Http\Controllers\Api;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\ComponentsTransformer;
|
use App\Http\Transformers\ComponentsTransformer;
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
use App\Events\ComponentCheckedIn;
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Database\Query\Builder;
|
use Illuminate\Database\Query\Builder;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class ComponentsController extends Controller
|
class ComponentsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -23,9 +25,8 @@ class ComponentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Component::class);
|
$this->authorize('view', Component::class);
|
||||||
|
|
||||||
|
@ -115,9 +116,8 @@ class ComponentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Component::class);
|
$this->authorize('create', Component::class);
|
||||||
$component = new Component;
|
$component = new Component;
|
||||||
|
@ -136,9 +136,8 @@ class ComponentsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Component::class);
|
$this->authorize('view', Component::class);
|
||||||
$component = Component::findOrFail($id);
|
$component = Component::findOrFail($id);
|
||||||
|
@ -155,9 +154,8 @@ class ComponentsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Component::class);
|
$this->authorize('update', Component::class);
|
||||||
$component = Component::findOrFail($id);
|
$component = Component::findOrFail($id);
|
||||||
|
@ -178,9 +176,8 @@ class ComponentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Component::class);
|
$this->authorize('delete', Component::class);
|
||||||
$component = Component::findOrFail($id);
|
$component = Component::findOrFail($id);
|
||||||
|
@ -197,9 +194,8 @@ class ComponentsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function getAssets(Request $request, $id)
|
public function getAssets(Request $request, $id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
$this->authorize('view', \App\Models\Asset::class);
|
||||||
|
|
||||||
|
@ -240,10 +236,8 @@ class ComponentsController extends Controller
|
||||||
* @since [v5.1.8]
|
* @since [v5.1.8]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $componentId
|
* @param int $componentId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function checkout(Request $request, $componentId)
|
public function checkout(Request $request, $componentId) : JsonResponse
|
||||||
{
|
{
|
||||||
// Check if the component exists
|
// Check if the component exists
|
||||||
if (!$component = Component::find($componentId)) {
|
if (!$component = Component::find($componentId)) {
|
||||||
|
@ -274,9 +268,9 @@ class ComponentsController extends Controller
|
||||||
|
|
||||||
$component->assets()->attach($component->id, [
|
$component->assets()->attach($component->id, [
|
||||||
'component_id' => $component->id,
|
'component_id' => $component->id,
|
||||||
'created_at' => \Carbon::now(),
|
'created_at' => Carbon::now(),
|
||||||
'assigned_qty' => $request->get('assigned_qty', 1),
|
'assigned_qty' => $request->get('assigned_qty', 1),
|
||||||
'user_id' => \Auth::id(),
|
'user_id' => auth()->id(),
|
||||||
'asset_id' => $request->get('assigned_to'),
|
'asset_id' => $request->get('assigned_to'),
|
||||||
'note' => $request->get('note'),
|
'note' => $request->get('note'),
|
||||||
]);
|
]);
|
||||||
|
@ -296,12 +290,10 @@ class ComponentsController extends Controller
|
||||||
* @since [v5.1.8]
|
* @since [v5.1.8]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param $component_asset_id
|
* @param $component_asset_id
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $component_asset_id)
|
public function checkin(Request $request, $component_asset_id) : JsonResponse
|
||||||
{
|
{
|
||||||
if ($component_assets = \DB::table('components_assets')->find($component_asset_id)) {
|
if ($component_assets = DB::table('components_assets')->find($component_asset_id)) {
|
||||||
|
|
||||||
if (is_null($component = Component::find($component_assets->component_id))) {
|
if (is_null($component = Component::find($component_assets->component_id))) {
|
||||||
|
|
||||||
|
@ -314,7 +306,7 @@ class ComponentsController extends Controller
|
||||||
|
|
||||||
if ($max_to_checkin > 1) {
|
if ($max_to_checkin > 1) {
|
||||||
|
|
||||||
$validator = \Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
"checkin_qty" => "required|numeric|between:1,$max_to_checkin"
|
"checkin_qty" => "required|numeric|between:1,$max_to_checkin"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -331,21 +323,21 @@ class ComponentsController extends Controller
|
||||||
// actually checked out.
|
// actually checked out.
|
||||||
$component_assets->assigned_qty = $qty_remaining_in_checkout;
|
$component_assets->assigned_qty = $qty_remaining_in_checkout;
|
||||||
|
|
||||||
\Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
|
Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
|
||||||
|
|
||||||
\DB::table('components_assets')->where('id',
|
DB::table('components_assets')->where('id',
|
||||||
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
|
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
|
||||||
|
|
||||||
// If the checked-in qty is exactly the same as the assigned_qty,
|
// If the checked-in qty is exactly the same as the assigned_qty,
|
||||||
// we can simply delete the associated components_assets record
|
// we can simply delete the associated components_assets record
|
||||||
if ($qty_remaining_in_checkout == 0) {
|
if ($qty_remaining_in_checkout == 0) {
|
||||||
\DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
|
DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset = Asset::find($component_assets->asset_id);
|
$asset = Asset::find($component_assets->asset_id);
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($component, $asset, \Auth::user(), $request->input('note'), \Carbon::now()));
|
event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkin.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkin.success')));
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api;
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\StoreConsumableRequest;
|
||||||
use App\Http\Transformers\ConsumablesTransformer;
|
use App\Http\Transformers\ConsumablesTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
@ -12,7 +13,8 @@ use App\Models\Consumable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class ConsumablesController extends Controller
|
class ConsumablesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -21,34 +23,13 @@ class ConsumablesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : array
|
||||||
{
|
{
|
||||||
$this->authorize('index', Consumable::class);
|
$this->authorize('index', Consumable::class);
|
||||||
|
|
||||||
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
|
$consumables = Consumable::with('company', 'location', 'category', 'supplier', 'manufacturer')
|
||||||
// Relations will be handled in query scopes a little further down.
|
->withCount('users as consumables_users_count');
|
||||||
$allowed_columns =
|
|
||||||
[
|
|
||||||
'id',
|
|
||||||
'name',
|
|
||||||
'order_number',
|
|
||||||
'min_amt',
|
|
||||||
'purchase_date',
|
|
||||||
'purchase_cost',
|
|
||||||
'company',
|
|
||||||
'category',
|
|
||||||
'model_number',
|
|
||||||
'item_no',
|
|
||||||
'qty',
|
|
||||||
'image',
|
|
||||||
'notes',
|
|
||||||
];
|
|
||||||
|
|
||||||
$consumables = Consumable::select('consumables.*')
|
|
||||||
->with('company', 'location', 'category', 'users', 'manufacturer');
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$consumables = $consumables->TextSearch(e($request->input('search')));
|
$consumables = $consumables->TextSearch(e($request->input('search')));
|
||||||
|
@ -90,15 +71,9 @@ class ConsumablesController extends Controller
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
$allowed_columns = ['id', 'name', 'order_number', 'min_amt', 'purchase_date', 'purchase_cost', 'company', 'category', 'model_number', 'item_no', 'manufacturer', 'location', 'qty', 'image'];
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
|
|
||||||
$sort_override = $request->input('sort');
|
switch ($request->input('sort')) {
|
||||||
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
|
|
||||||
|
|
||||||
|
|
||||||
switch ($sort_override) {
|
|
||||||
case 'category':
|
case 'category':
|
||||||
$consumables = $consumables->OrderCategory($order);
|
$consumables = $consumables->OrderCategory($order);
|
||||||
break;
|
break;
|
||||||
|
@ -112,10 +87,30 @@ class ConsumablesController extends Controller
|
||||||
$consumables = $consumables->OrderCompany($order);
|
$consumables = $consumables->OrderCompany($order);
|
||||||
break;
|
break;
|
||||||
case 'supplier':
|
case 'supplier':
|
||||||
$components = $consumables->OrderSupplier($order);
|
$consumables = $consumables->OrderSupplier($order);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$consumables = $consumables->orderBy($column_sort, $order);
|
// This array is what determines which fields should be allowed to be sorted on ON the table itself.
|
||||||
|
// These must match a column on the consumables table directly.
|
||||||
|
$allowed_columns = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'order_number',
|
||||||
|
'min_amt',
|
||||||
|
'purchase_date',
|
||||||
|
'purchase_cost',
|
||||||
|
'company',
|
||||||
|
'category',
|
||||||
|
'model_number',
|
||||||
|
'item_no',
|
||||||
|
'manufacturer',
|
||||||
|
'location',
|
||||||
|
'qty',
|
||||||
|
'image'
|
||||||
|
];
|
||||||
|
|
||||||
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||||
|
$consumables = $consumables->orderBy($sort, $order);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +126,8 @@ class ConsumablesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreConsumableRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Consumable::class);
|
$this->authorize('create', Consumable::class);
|
||||||
$consumable = new Consumable;
|
$consumable = new Consumable;
|
||||||
|
@ -152,9 +146,8 @@ class ConsumablesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Consumable::class);
|
$this->authorize('view', Consumable::class);
|
||||||
$consumable = Consumable::with('users')->findOrFail($id);
|
$consumable = Consumable::with('users')->findOrFail($id);
|
||||||
|
@ -169,9 +162,8 @@ class ConsumablesController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(StoreConsumableRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Consumable::class);
|
$this->authorize('update', Consumable::class);
|
||||||
$consumable = Consumable::findOrFail($id);
|
$consumable = Consumable::findOrFail($id);
|
||||||
|
@ -191,9 +183,8 @@ class ConsumablesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Consumable::class);
|
$this->authorize('delete', Consumable::class);
|
||||||
$consumable = Consumable::findOrFail($id);
|
$consumable = Consumable::findOrFail($id);
|
||||||
|
@ -210,9 +201,8 @@ class ConsumablesController extends Controller
|
||||||
* @see \App\Http\Controllers\Consumables\ConsumablesController::getView() method that returns the form.
|
* @see \App\Http\Controllers\Consumables\ConsumablesController::getView() method that returns the form.
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $consumableId
|
* @param int $consumableId
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getDataView($consumableId)
|
public function getDataView($consumableId) : array
|
||||||
{
|
{
|
||||||
$consumable = Consumable::with(['consumableAssignments'=> function ($query) {
|
$consumable = Consumable::with(['consumableAssignments'=> function ($query) {
|
||||||
$query->orderBy($query->getModel()->getTable().'.created_at', 'DESC');
|
$query->orderBy($query->getModel()->getTable().'.created_at', 'DESC');
|
||||||
|
@ -251,9 +241,8 @@ class ConsumablesController extends Controller
|
||||||
* @author [A. Gutierrez] [<andres@baller.tv>]
|
* @author [A. Gutierrez] [<andres@baller.tv>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v4.9.5]
|
* @since [v4.9.5]
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function checkout(Request $request, $id)
|
public function checkout(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
// Check if the consumable exists
|
// Check if the consumable exists
|
||||||
if (!$consumable = Consumable::with('users')->find($id)) {
|
if (!$consumable = Consumable::with('users')->find($id)) {
|
||||||
|
@ -277,7 +266,6 @@ class ConsumablesController extends Controller
|
||||||
if (!$user = User::find($request->input('assigned_to'))) {
|
if (!$user = User::find($request->input('assigned_to'))) {
|
||||||
// Return error message
|
// Return error message
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
||||||
\Log::debug('No valid user');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the consumable data
|
// Update the consumable data
|
||||||
|
@ -292,7 +280,7 @@ class ConsumablesController extends Controller
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||||
|
|
||||||
|
@ -303,7 +291,7 @@ class ConsumablesController extends Controller
|
||||||
*
|
*
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
$consumables = Consumable::select([
|
$consumables = Consumable::select([
|
||||||
'consumables.id',
|
'consumables.id',
|
||||||
|
|
|
@ -8,7 +8,8 @@ use App\Http\Transformers\CustomFieldsTransformer;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use App\Models\CustomFieldset;
|
use App\Models\CustomFieldset;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class CustomFieldsController extends Controller
|
class CustomFieldsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -20,7 +21,7 @@ class CustomFieldsController extends Controller
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : array
|
||||||
{
|
{
|
||||||
$this->authorize('index', CustomField::class);
|
$this->authorize('index', CustomField::class);
|
||||||
$fields = CustomField::get();
|
$fields = CustomField::get();
|
||||||
|
@ -33,9 +34,8 @@ class CustomFieldsController extends Controller
|
||||||
* @author [V. Cordes] [<volker@fdatek.de>]
|
* @author [V. Cordes] [<volker@fdatek.de>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v4.1.10]
|
* @since [v4.1.10]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', CustomField::class);
|
$this->authorize('view', CustomField::class);
|
||||||
if ($field = CustomField::find($id)) {
|
if ($field = CustomField::find($id)) {
|
||||||
|
@ -52,9 +52,8 @@ class CustomFieldsController extends Controller
|
||||||
* @since [v4.1.10]
|
* @since [v4.1.10]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', CustomField::class);
|
$this->authorize('update', CustomField::class);
|
||||||
$field = CustomField::findOrFail($id);
|
$field = CustomField::findOrFail($id);
|
||||||
|
@ -86,9 +85,8 @@ class CustomFieldsController extends Controller
|
||||||
* @author [V. Cordes] [<volker@fdatek.de>]
|
* @author [V. Cordes] [<volker@fdatek.de>]
|
||||||
* @since [v4.1.10]
|
* @since [v4.1.10]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', CustomField::class);
|
$this->authorize('create', CustomField::class);
|
||||||
$field = new CustomField;
|
$field = new CustomField;
|
||||||
|
@ -136,7 +134,7 @@ class CustomFieldsController extends Controller
|
||||||
return $fieldset->fields()->sync($fields);
|
return $fieldset->fields()->sync($fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function associate(Request $request, $field_id)
|
public function associate(Request $request, $field_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', CustomFieldset::class);
|
$this->authorize('update', CustomFieldset::class);
|
||||||
|
|
||||||
|
@ -155,10 +153,9 @@ class CustomFieldsController extends Controller
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disassociate(Request $request, $field_id)
|
public function disassociate(Request $request, $field_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', CustomFieldset::class);
|
$this->authorize('update', CustomFieldset::class);
|
||||||
|
|
||||||
$field = CustomField::findOrFail($field_id);
|
$field = CustomField::findOrFail($field_id);
|
||||||
|
|
||||||
$fieldset_id = $request->input('fieldset_id');
|
$fieldset_id = $request->input('fieldset_id');
|
||||||
|
@ -179,9 +176,8 @@ class CustomFieldsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function destroy($field_id)
|
public function destroy($field_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$field = CustomField::findOrFail($field_id);
|
$field = CustomField::findOrFail($field_id);
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ use App\Http\Transformers\CustomFieldsTransformer;
|
||||||
use App\Models\CustomFieldset;
|
use App\Models\CustomFieldset;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Redirect;
|
use Illuminate\Http\JsonResponse;
|
||||||
use View;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Custom Asset Fieldsets for
|
* This controller handles all actions related to Custom Asset Fieldsets for
|
||||||
|
@ -30,9 +29,8 @@ class CustomFieldsetsController extends Controller
|
||||||
* @author [Josh Gibson]
|
* @author [Josh Gibson]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : array
|
||||||
{
|
{
|
||||||
$this->authorize('index', CustomField::class);
|
$this->authorize('index', CustomField::class);
|
||||||
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
|
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
|
||||||
|
@ -46,9 +44,8 @@ class CustomFieldsetsController extends Controller
|
||||||
* @author [Josh Gibson]
|
* @author [Josh Gibson]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', CustomField::class);
|
$this->authorize('view', CustomField::class);
|
||||||
if ($fieldset = CustomFieldset::find($id)) {
|
if ($fieldset = CustomFieldset::find($id)) {
|
||||||
|
@ -65,9 +62,8 @@ class CustomFieldsetsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', CustomField::class);
|
$this->authorize('update', CustomField::class);
|
||||||
$fieldset = CustomFieldset::findOrFail($id);
|
$fieldset = CustomFieldset::findOrFail($id);
|
||||||
|
@ -86,9 +82,8 @@ class CustomFieldsetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', CustomField::class);
|
$this->authorize('create', CustomField::class);
|
||||||
$fieldset = new CustomFieldset;
|
$fieldset = new CustomFieldset;
|
||||||
|
@ -118,9 +113,8 @@ class CustomFieldsetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', CustomField::class);
|
$this->authorize('delete', CustomField::class);
|
||||||
$fieldset = CustomFieldset::findOrFail($id);
|
$fieldset = CustomFieldset::findOrFail($id);
|
||||||
|
@ -147,7 +141,7 @@ class CustomFieldsetsController extends Controller
|
||||||
* @param $fieldsetId
|
* @param $fieldsetId
|
||||||
* @return string JSON
|
* @return string JSON
|
||||||
*/
|
*/
|
||||||
public function fields($id)
|
public function fields($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', CustomField::class);
|
$this->authorize('view', CustomField::class);
|
||||||
$set = CustomFieldset::findOrFail($id);
|
$set = CustomFieldset::findOrFail($id);
|
||||||
|
@ -164,14 +158,11 @@ class CustomFieldsetsController extends Controller
|
||||||
* @param $fieldsetId
|
* @param $fieldsetId
|
||||||
* @return string JSON
|
* @return string JSON
|
||||||
*/
|
*/
|
||||||
public function fieldsWithDefaultValues($fieldsetId, $modelId)
|
public function fieldsWithDefaultValues($fieldsetId, $modelId) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', CustomField::class);
|
$this->authorize('view', CustomField::class);
|
||||||
|
|
||||||
$set = CustomFieldset::findOrFail($fieldsetId);
|
$set = CustomFieldset::findOrFail($fieldsetId);
|
||||||
|
|
||||||
$fields = $set->fields;
|
$fields = $set->fields;
|
||||||
|
|
||||||
return (new CustomFieldsTransformer)->transformCustomFieldsWithDefaultValues($fields, $modelId, $fields->count());
|
return (new CustomFieldsTransformer)->transformCustomFieldsWithDefaultValues($fields, $modelId, $fields->count());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,11 @@ use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\DepartmentsTransformer;
|
use App\Http\Transformers\DepartmentsTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\Department;
|
use App\Models\Department;
|
||||||
use Auth;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class DepartmentsController extends Controller
|
class DepartmentsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -20,9 +19,8 @@ class DepartmentsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Godfrey Martinez] [<snipe@snipe.net>]
|
* @author [Godfrey Martinez] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Department::class);
|
$this->authorize('view', Department::class);
|
||||||
$allowed_columns = ['id', 'name', 'image', 'users_count'];
|
$allowed_columns = ['id', 'name', 'image', 'users_count'];
|
||||||
|
@ -91,16 +89,15 @@ class DepartmentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Department::class);
|
$this->authorize('create', Department::class);
|
||||||
$department = new Department;
|
$department = new Department;
|
||||||
$department->fill($request->all());
|
$department->fill($request->all());
|
||||||
$department = $request->handleImages($department);
|
$department = $request->handleImages($department);
|
||||||
|
|
||||||
$department->user_id = Auth::user()->id;
|
$department->user_id = auth()->id();
|
||||||
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
|
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
|
||||||
|
|
||||||
if ($department->save()) {
|
if ($department->save()) {
|
||||||
|
@ -116,13 +113,11 @@ class DepartmentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Department::class);
|
$this->authorize('view', Department::class);
|
||||||
$department = Department::findOrFail($id);
|
$department = Department::findOrFail($id);
|
||||||
|
|
||||||
return (new DepartmentsTransformer)->transformDepartment($department);
|
return (new DepartmentsTransformer)->transformDepartment($department);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,9 +128,8 @@ class DepartmentsController extends Controller
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Department::class);
|
$this->authorize('update', Department::class);
|
||||||
$department = Department::findOrFail($id);
|
$department = Department::findOrFail($id);
|
||||||
|
@ -156,9 +150,8 @@ class DepartmentsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $locationId
|
* @param int $locationId
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$department = Department::findOrFail($id);
|
$department = Department::findOrFail($id);
|
||||||
|
|
||||||
|
@ -180,7 +173,7 @@ class DepartmentsController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
|
|
|
@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\DepreciationsTransformer;
|
use App\Http\Transformers\DepreciationsTransformer;
|
||||||
use App\Models\Depreciation;
|
use App\Models\Depreciation;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class DepreciationsController extends Controller
|
class DepreciationsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -15,9 +16,8 @@ class DepreciationsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Depreciation::class);
|
$this->authorize('view', Depreciation::class);
|
||||||
$allowed_columns = ['id','name','months','depreciation_min','created_at'];
|
$allowed_columns = ['id','name','months','depreciation_min','created_at'];
|
||||||
|
@ -48,9 +48,8 @@ class DepreciationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Depreciation::class);
|
$this->authorize('create', Depreciation::class);
|
||||||
$depreciation = new Depreciation;
|
$depreciation = new Depreciation;
|
||||||
|
@ -69,9 +68,8 @@ class DepreciationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Depreciation::class);
|
$this->authorize('view', Depreciation::class);
|
||||||
$depreciation = Depreciation::findOrFail($id);
|
$depreciation = Depreciation::findOrFail($id);
|
||||||
|
@ -86,9 +84,8 @@ class DepreciationsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Depreciation::class);
|
$this->authorize('update', Depreciation::class);
|
||||||
$depreciation = Depreciation::findOrFail($id);
|
$depreciation = Depreciation::findOrFail($id);
|
||||||
|
@ -107,9 +104,8 @@ class DepreciationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Depreciation::class);
|
$this->authorize('delete', Depreciation::class);
|
||||||
$depreciation = Depreciation::withCount('models as models_count')->findOrFail($id);
|
$depreciation = Depreciation::withCount('models as models_count')->findOrFail($id);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\GroupsTransformer;
|
use App\Http\Transformers\GroupsTransformer;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Auth;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
|
||||||
class GroupsController extends Controller
|
class GroupsController extends Controller
|
||||||
|
@ -17,9 +17,8 @@ class GroupsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
|
|
||||||
|
@ -56,19 +55,21 @@ class GroupsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = new Group;
|
$group = new Group;
|
||||||
|
// Get all the available permissions
|
||||||
|
$permissions = config('permissions');
|
||||||
|
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
|
||||||
|
|
||||||
$group->name = $request->input('name');
|
$group->name = $request->input('name');
|
||||||
$group->created_by = Auth::user()->id;
|
$group->created_by = auth()->id();
|
||||||
$group->permissions = json_encode($request->input('permissions')); // Todo - some JSON validation stuff here
|
$group->permissions = json_encode($request->input('permissions', $groupPermissions));
|
||||||
|
|
||||||
if ($group->save()) {
|
if ($group->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.create.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new GroupsTransformer)->transformGroup($group), trans('admin/groups/message.success.create')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
||||||
|
@ -80,13 +81,11 @@ class GroupsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = Group::findOrFail($id);
|
$group = Group::findOrFail($id);
|
||||||
|
|
||||||
return (new GroupsTransformer)->transformGroup($group);
|
return (new GroupsTransformer)->transformGroup($group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,9 +96,8 @@ class GroupsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = Group::findOrFail($id);
|
$group = Group::findOrFail($id);
|
||||||
|
@ -108,7 +106,7 @@ class GroupsController extends Controller
|
||||||
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
||||||
|
|
||||||
if ($group->save()) {
|
if ($group->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', (new GroupsTransformer)->transformGroup($group), trans('admin/groups/message.success.update')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $group->getErrors()));
|
||||||
|
@ -120,9 +118,8 @@ class GroupsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('superadmin');
|
$this->authorize('superadmin');
|
||||||
$group = Group::findOrFail($id);
|
$group = Group::findOrFail($id);
|
||||||
|
|
|
@ -9,22 +9,23 @@ use App\Http\Transformers\ImportsTransformer;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Import;
|
use App\Models\Import;
|
||||||
use Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Database\Eloquent\JsonEncodingException;
|
use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||||
use Illuminate\Support\Facades\Request;
|
use Illuminate\Support\Facades\Request;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use League\Csv\Reader;
|
use League\Csv\Reader;
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class ImportController extends Controller
|
class ImportController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('import');
|
$this->authorize('import');
|
||||||
$imports = Import::latest()->get();
|
$imports = Import::latest()->get();
|
||||||
|
@ -36,9 +37,8 @@ class ImportController extends Controller
|
||||||
* Process and store a CSV upload file.
|
* Process and store a CSV upload file.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function store()
|
public function store() : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('import');
|
$this->authorize('import');
|
||||||
if (! config('app.lock_passwords')) {
|
if (! config('app.lock_passwords')) {
|
||||||
|
@ -151,18 +151,17 @@ class ImportController extends Controller
|
||||||
* Processes the specified Import.
|
* Processes the specified Import.
|
||||||
*
|
*
|
||||||
* @param int $import_id
|
* @param int $import_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function process(ItemImportRequest $request, $import_id)
|
public function process(ItemImportRequest $request, $import_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('import');
|
$this->authorize('import');
|
||||||
|
|
||||||
// Run a backup immediately before processing
|
// Run a backup immediately before processing
|
||||||
if ($request->get('run-backup')) {
|
if ($request->get('run-backup')) {
|
||||||
\Log::debug('Backup manually requested via importer');
|
Log::debug('Backup manually requested via importer');
|
||||||
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]);
|
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]);
|
||||||
} else {
|
} else {
|
||||||
\Log::debug('NO BACKUP requested via importer');
|
Log::debug('NO BACKUP requested via importer');
|
||||||
}
|
}
|
||||||
|
|
||||||
$import = Import::find($import_id);
|
$import = Import::find($import_id);
|
||||||
|
@ -211,9 +210,8 @@ class ImportController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $import_id
|
* @param int $import_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($import_id)
|
public function destroy($import_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Asset::class);
|
$this->authorize('create', Asset::class);
|
||||||
|
|
||||||
|
@ -230,6 +228,8 @@ class ImportController extends Controller
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
|
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use App\Http\Transformers\LabelsTransformer;
|
||||||
use App\Models\Labels\Label;
|
use App\Models\Labels\Label;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\ItemNotFoundException;
|
use Illuminate\Support\ItemNotFoundException;
|
||||||
use Auth;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class LabelsController extends Controller
|
class LabelsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,8 @@ class LabelsController extends Controller
|
||||||
* Returns JSON listing of all labels.
|
* Returns JSON listing of all labels.
|
||||||
*
|
*
|
||||||
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Label::class);
|
$this->authorize('view', Label::class);
|
||||||
|
|
||||||
|
@ -50,9 +49,8 @@ class LabelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
* @author Grant Le Roux <grant.leroux+snipe-it@gmail.com>
|
||||||
* @param string $labelName
|
* @param string $labelName
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function show(string $labelName)
|
public function show(string $labelName) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$labelName = str_replace('/', '\\', $labelName);
|
$labelName = str_replace('/', '\\', $labelName);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Models\Asset;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Auth;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class LicenseSeatsController extends Controller
|
class LicenseSeatsController extends Controller
|
||||||
|
@ -19,11 +19,10 @@ class LicenseSeatsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $licenseId
|
* @param int $licenseId
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request, $licenseId)
|
public function index(Request $request, $licenseId) : JsonResponse | array
|
||||||
{
|
{
|
||||||
//
|
|
||||||
if ($license = License::find($licenseId)) {
|
if ($license = License::find($licenseId)) {
|
||||||
$this->authorize('view', $license);
|
$this->authorize('view', $license);
|
||||||
|
|
||||||
|
@ -64,11 +63,10 @@ class LicenseSeatsController extends Controller
|
||||||
*
|
*
|
||||||
* @param int $licenseId
|
* @param int $licenseId
|
||||||
* @param int $seatId
|
* @param int $seatId
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($licenseId, $seatId)
|
public function show($licenseId, $seatId) : JsonResponse | array
|
||||||
{
|
{
|
||||||
//
|
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
// sanity checks:
|
// sanity checks:
|
||||||
// 1. does the license seat exist?
|
// 1. does the license seat exist?
|
||||||
|
@ -89,19 +87,18 @@ class LicenseSeatsController extends Controller
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $licenseId
|
* @param int $licenseId
|
||||||
* @param int $seatId
|
* @param int $seatId
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $licenseId, $seatId)
|
public function update(Request $request, $licenseId, $seatId) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('checkout', License::class);
|
$this->authorize('checkout', License::class);
|
||||||
|
|
||||||
// sanity checks:
|
|
||||||
// 1. does the license seat exist?
|
|
||||||
if (! $licenseSeat = LicenseSeat::find($seatId)) {
|
if (! $licenseSeat = LicenseSeat::find($seatId)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat not found'));
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat not found'));
|
||||||
}
|
}
|
||||||
// 2. does the seat belong to the specified license?
|
|
||||||
if (! $license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
|
$license = $licenseSeat->license()->first();
|
||||||
|
if (!$license || $license->id != intval($licenseId)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat does not belong to the specified license'));
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat does not belong to the specified license'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +107,7 @@ class LicenseSeatsController extends Controller
|
||||||
|
|
||||||
// attempt to update the license seat
|
// attempt to update the license seat
|
||||||
$licenseSeat->fill($request->all());
|
$licenseSeat->fill($request->all());
|
||||||
$licenseSeat->user_id = Auth::user()->id;
|
$licenseSeat->user_id = auth()->id();
|
||||||
|
|
||||||
// check if this update is a checkin operation
|
// check if this update is a checkin operation
|
||||||
// 1. are relevant fields touched at all?
|
// 1. are relevant fields touched at all?
|
||||||
|
|
|
@ -4,14 +4,12 @@ namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\LicenseSeatsTransformer;
|
|
||||||
use App\Http\Transformers\LicensesTransformer;
|
use App\Http\Transformers\LicensesTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\LicenseSeat;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class LicensesController extends Controller
|
class LicensesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -21,9 +19,8 @@ class LicensesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
|
||||||
|
@ -156,11 +153,9 @@ class LicensesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
//
|
|
||||||
$this->authorize('create', License::class);
|
$this->authorize('create', License::class);
|
||||||
$license = new License;
|
$license = new License;
|
||||||
$license->fill($request->all());
|
$license->fill($request->all());
|
||||||
|
@ -177,9 +172,8 @@ class LicensesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
$license = License::withCount('freeSeats')->findOrFail($id);
|
$license = License::withCount('freeSeats')->findOrFail($id);
|
||||||
|
@ -195,9 +189,8 @@ class LicensesController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
$this->authorize('update', License::class);
|
$this->authorize('update', License::class);
|
||||||
|
@ -218,9 +211,8 @@ class LicensesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
$license = License::findOrFail($id);
|
$license = License::findOrFail($id);
|
||||||
|
@ -248,7 +240,7 @@ class LicensesController extends Controller
|
||||||
*
|
*
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
$licenses = License::select([
|
$licenses = License::select([
|
||||||
'licenses.id',
|
'licenses.id',
|
||||||
|
|
|
@ -11,6 +11,7 @@ use App\Models\Location;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class LocationsController extends Controller
|
class LocationsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -21,7 +22,7 @@ class LocationsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Location::class);
|
$this->authorize('view', Location::class);
|
||||||
$allowed_columns = [
|
$allowed_columns = [
|
||||||
|
@ -138,9 +139,8 @@ class LocationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Location::class);
|
$this->authorize('create', Location::class);
|
||||||
$location = new Location;
|
$location = new Location;
|
||||||
|
@ -160,9 +160,8 @@ class LocationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Location::class);
|
$this->authorize('view', Location::class);
|
||||||
$location = Location::with('parent', 'manager', 'children')
|
$location = Location::with('parent', 'manager', 'children')
|
||||||
|
@ -199,9 +198,8 @@ class LocationsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Location::class);
|
$this->authorize('update', Location::class);
|
||||||
$location = Location::findOrFail($id);
|
$location = Location::findOrFail($id);
|
||||||
|
@ -230,9 +228,8 @@ class LocationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Location::class);
|
$this->authorize('delete', Location::class);
|
||||||
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||||
|
@ -244,7 +241,7 @@ class LocationsController extends Controller
|
||||||
|
|
||||||
if (! $location->isDeletable()) {
|
if (! $location->isDeletable()) {
|
||||||
return response()
|
return response()
|
||||||
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
|
->json(Helper::formatStandardApiResponse('error', null, trans('admin/locations/message.assoc_users')));
|
||||||
}
|
}
|
||||||
$this->authorize('delete', $location);
|
$this->authorize('delete', $location);
|
||||||
$location->delete();
|
$location->delete();
|
||||||
|
@ -280,7 +277,7 @@ class LocationsController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
// If a user is in the process of editing their profile, as determined by the referrer,
|
// If a user is in the process of editing their profile, as determined by the referrer,
|
||||||
// then we check that they have permission to edit their own location.
|
// then we check that they have permission to edit their own location.
|
||||||
|
@ -325,7 +322,6 @@ class LocationsController extends Controller
|
||||||
|
|
||||||
$paginated_results = new LengthAwarePaginator($locations_formatted->forPage($page, 500), $locations_formatted->count(), 500, $page, []);
|
$paginated_results = new LengthAwarePaginator($locations_formatted->forPage($page, 500), $locations_formatted->count(), 500, $page, []);
|
||||||
|
|
||||||
//return [];
|
|
||||||
return (new SelectlistTransformer)->transformSelectlist($paginated_results);
|
return (new SelectlistTransformer)->transformSelectlist($paginated_results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ use App\Models\Actionlog;
|
||||||
use App\Models\Manufacturer;
|
use App\Models\Manufacturer;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class ManufacturersController extends Controller
|
class ManufacturersController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ class ManufacturersController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Manufacturer::class);
|
$this->authorize('view', Manufacturer::class);
|
||||||
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'warranty_lookup_url', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
|
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'warranty_lookup_url', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
|
||||||
|
@ -83,9 +83,8 @@ class ManufacturersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Manufacturer::class);
|
$this->authorize('create', Manufacturer::class);
|
||||||
$manufacturer = new Manufacturer;
|
$manufacturer = new Manufacturer;
|
||||||
|
@ -105,9 +104,8 @@ class ManufacturersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Manufacturer::class);
|
$this->authorize('view', Manufacturer::class);
|
||||||
$manufacturer = Manufacturer::withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count')->findOrFail($id);
|
$manufacturer = Manufacturer::withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count')->findOrFail($id);
|
||||||
|
@ -122,9 +120,8 @@ class ManufacturersController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Manufacturer::class);
|
$this->authorize('update', Manufacturer::class);
|
||||||
$manufacturer = Manufacturer::findOrFail($id);
|
$manufacturer = Manufacturer::findOrFail($id);
|
||||||
|
@ -144,9 +141,8 @@ class ManufacturersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Manufacturer::class);
|
$this->authorize('delete', Manufacturer::class);
|
||||||
$manufacturer = Manufacturer::findOrFail($id);
|
$manufacturer = Manufacturer::findOrFail($id);
|
||||||
|
@ -167,10 +163,9 @@ class ManufacturersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.3.4]
|
* @since [v6.3.4]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function restore($id)
|
public function restore($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Manufacturer::class);
|
$this->authorize('delete', Manufacturer::class);
|
||||||
|
|
||||||
|
@ -186,7 +181,7 @@ class ManufacturersController extends Controller
|
||||||
$logaction->item_type = Manufacturer::class;
|
$logaction->item_type = Manufacturer::class;
|
||||||
$logaction->item_id = $manufacturer->id;
|
$logaction->item_id = $manufacturer->id;
|
||||||
$logaction->created_at = date('Y-m-d H:i:s');
|
$logaction->created_at = date('Y-m-d H:i:s');
|
||||||
$logaction->user_id = Auth::user()->id;
|
$logaction->user_id = auth()->id();
|
||||||
$logaction->logaction('restore');
|
$logaction->logaction('restore');
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200);
|
return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200);
|
||||||
|
@ -206,7 +201,7 @@ class ManufacturersController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
|
|
|
@ -7,6 +7,8 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\PredefinedKitsTransformer;
|
use App\Http\Transformers\PredefinedKitsTransformer;
|
||||||
use App\Models\PredefinedKit;
|
use App\Models\PredefinedKit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
|
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
|
||||||
|
@ -18,7 +20,7 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$allowed_columns = ['id', 'name'];
|
$allowed_columns = ['id', 'name'];
|
||||||
|
@ -47,9 +49,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', PredefinedKit::class);
|
$this->authorize('create', PredefinedKit::class);
|
||||||
$kit = new PredefinedKit;
|
$kit = new PredefinedKit;
|
||||||
|
@ -66,9 +67,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($id);
|
$kit = PredefinedKit::findOrFail($id);
|
||||||
|
@ -81,9 +81,8 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id kit id
|
* @param int $id kit id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($id);
|
$kit = PredefinedKit::findOrFail($id);
|
||||||
|
@ -100,9 +99,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', PredefinedKit::class);
|
$this->authorize('delete', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($id);
|
$kit = PredefinedKit::findOrFail($id);
|
||||||
|
@ -123,7 +121,7 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
$kits = PredefinedKit::select([
|
$kits = PredefinedKit::select([
|
||||||
'id',
|
'id',
|
||||||
|
@ -145,7 +143,7 @@ class PredefinedKitsController extends Controller
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function indexLicenses($kit_id)
|
public function indexLicenses($kit_id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -160,7 +158,7 @@ class PredefinedKitsController extends Controller
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function storeLicense(Request $request, $kit_id)
|
public function storeLicense(Request $request, $kit_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
|
|
||||||
|
@ -186,9 +184,8 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function updateLicense(Request $request, $kit_id, $license_id)
|
public function updateLicense(Request $request, $kit_id, $license_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -205,9 +202,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function detachLicense($kit_id, $license_id)
|
public function detachLicense($kit_id, $license_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -221,9 +217,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function indexModels($kit_id)
|
public function indexModels($kit_id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -236,9 +231,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Store the specified resource.
|
* Store the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function storeModel(Request $request, $kit_id)
|
public function storeModel(Request $request, $kit_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
|
|
||||||
|
@ -264,9 +258,8 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function updateModel(Request $request, $kit_id, $model_id)
|
public function updateModel(Request $request, $kit_id, $model_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -283,9 +276,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function detachModel($kit_id, $model_id)
|
public function detachModel($kit_id, $model_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -299,9 +291,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function indexConsumables($kit_id)
|
public function indexConsumables($kit_id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -314,9 +305,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Store the specified resource.
|
* Store the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function storeConsumable(Request $request, $kit_id)
|
public function storeConsumable(Request $request, $kit_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
|
|
||||||
|
@ -342,9 +332,8 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function updateConsumable(Request $request, $kit_id, $consumable_id)
|
public function updateConsumable(Request $request, $kit_id, $consumable_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -361,9 +350,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function detachConsumable($kit_id, $consumable_id)
|
public function detachConsumable($kit_id, $consumable_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -377,9 +365,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function indexAccessories($kit_id)
|
public function indexAccessories($kit_id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', PredefinedKit::class);
|
$this->authorize('view', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -392,9 +379,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Store the specified resource.
|
* Store the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function storeAccessory(Request $request, $kit_id)
|
public function storeAccessory(Request $request, $kit_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
|
|
||||||
|
@ -420,9 +406,8 @@ class PredefinedKitsController extends Controller
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function updateAccessory(Request $request, $kit_id, $accessory_id)
|
public function updateAccessory(Request $request, $kit_id, $accessory_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
@ -439,9 +424,8 @@ class PredefinedKitsController extends Controller
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $kit_id
|
* @param int $kit_id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function detachAccessory($kit_id, $accessory_id)
|
public function detachAccessory($kit_id, $accessory_id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', PredefinedKit::class);
|
$this->authorize('update', PredefinedKit::class);
|
||||||
$kit = PredefinedKit::findOrFail($kit_id);
|
$kit = PredefinedKit::findOrFail($kit_id);
|
||||||
|
|
|
@ -6,13 +6,13 @@ use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\CheckoutRequest;
|
use App\Models\CheckoutRequest;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Laravel\Passport\TokenRepository;
|
use Laravel\Passport\TokenRepository;
|
||||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class ProfileController extends Controller
|
class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -42,12 +42,10 @@ class ProfileController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.3.0]
|
* @since [v4.3.0]
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function requestedAssets()
|
public function requestedAssets() : array
|
||||||
{
|
{
|
||||||
$checkoutRequests = CheckoutRequest::where('user_id', '=', Auth::user()->id)->get();
|
$checkoutRequests = CheckoutRequest::where('user_id', '=', auth()->id())->get();
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
$show_field = array();
|
$show_field = array();
|
||||||
|
@ -95,10 +93,9 @@ class ProfileController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.0.5]
|
* @since [v6.0.5]
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function createApiToken(Request $request) {
|
public function createApiToken(Request $request) : JsonResponse
|
||||||
|
{
|
||||||
|
|
||||||
if (!Gate::allows('self.api')) {
|
if (!Gate::allows('self.api')) {
|
||||||
abort(403);
|
abort(403);
|
||||||
|
@ -106,14 +103,14 @@ class ProfileController extends Controller
|
||||||
|
|
||||||
$accessTokenName = $request->input('name', 'Auth Token');
|
$accessTokenName = $request->input('name', 'Auth Token');
|
||||||
|
|
||||||
if ($accessToken = Auth::user()->createToken($accessTokenName)->accessToken) {
|
if ($accessToken = auth()->user()->createToken($accessTokenName)->accessToken) {
|
||||||
|
|
||||||
// Get the ID so we can return that with the payload
|
// Get the ID so we can return that with the payload
|
||||||
$token = DB::table('oauth_access_tokens')->where('user_id', '=', Auth::user()->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first();
|
$token = DB::table('oauth_access_tokens')->where('user_id', '=', auth()->id())->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first();
|
||||||
$accessTokenData['id'] = $token->id;
|
$accessTokenData['id'] = $token->id;
|
||||||
$accessTokenData['token'] = $accessToken;
|
$accessTokenData['token'] = $accessToken;
|
||||||
$accessTokenData['name'] = $accessTokenName;
|
$accessTokenData['name'] = $accessTokenName;
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $accessTokenData, 'Personal access token '.$accessTokenName.' created successfully'));
|
return response()->json(Helper::formatStandardApiResponse('success', $accessTokenData, trans('account/general.personal_api_keys_success', ['key' => $accessTokenName])));
|
||||||
}
|
}
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Token could not be created.'));
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Token could not be created.'));
|
||||||
|
|
||||||
|
@ -125,17 +122,16 @@ class ProfileController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.0.5]
|
* @since [v6.0.5]
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function deleteApiToken($tokenId) {
|
public function deleteApiToken($tokenId) : Response
|
||||||
|
{
|
||||||
|
|
||||||
if (!Gate::allows('self.api')) {
|
if (!Gate::allows('self.api')) {
|
||||||
abort(403);
|
abort(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->tokenRepository->findForUser(
|
$token = $this->tokenRepository->findForUser(
|
||||||
$tokenId, Auth::user()->getAuthIdentifier()
|
$tokenId, auth()->user()->getAuthIdentifier()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (is_null($token)) {
|
if (is_null($token)) {
|
||||||
|
@ -154,16 +150,15 @@ class ProfileController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.0.5]
|
* @since [v6.0.5]
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function showApiTokens(Request $request) {
|
public function showApiTokens() : JsonResponse
|
||||||
|
{
|
||||||
|
|
||||||
if (!Gate::allows('self.api')) {
|
if (!Gate::allows('self.api')) {
|
||||||
abort(403);
|
abort(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tokens = $this->tokenRepository->forUser(Auth::user()->getAuthIdentifier());
|
$tokens = $this->tokenRepository->forUser(auth()->user()->getAuthIdentifier());
|
||||||
$token_values = $tokens->load('client')->filter(function ($token) {
|
$token_values = $tokens->load('client')->filter(function ($token) {
|
||||||
return $token->client->personal_access_client && ! $token->revoked;
|
return $token->client->personal_access_client && ! $token->revoked;
|
||||||
})->values();
|
})->values();
|
||||||
|
|
|
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\ActionlogsTransformer;
|
use App\Http\Transformers\ActionlogsTransformer;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class ReportsController extends Controller
|
class ReportsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -14,9 +15,8 @@ class ReportsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('reports.view');
|
$this->authorize('reports.view');
|
||||||
|
|
||||||
|
@ -78,13 +78,14 @@ class ReportsController extends Controller
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$total = $actionlogs->count();
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $actionlogs->count()) ? $actionlogs->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $total) ? $total : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||||
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
|
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
|
||||||
$total = $actionlogs->count();
|
|
||||||
|
|
||||||
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
|
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
|
||||||
|
|
||||||
|
|
|
@ -9,42 +9,38 @@ use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Ldap;
|
use App\Models\Ldap;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Mail;
|
|
||||||
use App\Notifications\SlackTest;
|
|
||||||
use App\Notifications\MailTest;
|
use App\Notifications\MailTest;
|
||||||
use GuzzleHttp\Client;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use App\Http\Requests\SlackSettingsRequest;
|
|
||||||
use App\Http\Transformers\LoginAttemptsTransformer;
|
use App\Http\Transformers\LoginAttemptsTransformer;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
|
|
||||||
class SettingsController extends Controller
|
class SettingsController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public function ldaptest()
|
public function ldaptest() : JsonResponse
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
|
||||||
if ($settings->ldap_enabled!='1') {
|
if ($settings->ldap_enabled!='1') {
|
||||||
\Log::debug('LDAP is not enabled cannot test.');
|
Log::debug('LDAP is not enabled cannot test.');
|
||||||
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug('Preparing to test LDAP connection');
|
Log::debug('Preparing to test LDAP connection');
|
||||||
|
|
||||||
$message = []; //where we collect together test messages
|
$message = []; //where we collect together test messages
|
||||||
try {
|
try {
|
||||||
$connection = Ldap::connectToLdap();
|
$connection = Ldap::connectToLdap();
|
||||||
try {
|
try {
|
||||||
$message['bind'] = ['message' => 'Successfully bound to LDAP server.'];
|
$message['bind'] = ['message' => 'Successfully bound to LDAP server.'];
|
||||||
\Log::debug('attempting to bind to LDAP for LDAP test');
|
Log::debug('attempting to bind to LDAP for LDAP test');
|
||||||
Ldap::bindAdminToLdap($connection);
|
Ldap::bindAdminToLdap($connection);
|
||||||
$message['login'] = [
|
$message['login'] = [
|
||||||
'message' => 'Successfully connected to LDAP server.',
|
'message' => 'Successfully connected to LDAP server.',
|
||||||
|
@ -75,24 +71,24 @@ class SettingsController extends Controller
|
||||||
|
|
||||||
return response()->json($message, 200);
|
return response()->json($message, 200);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Bind failed');
|
Log::debug('Bind failed');
|
||||||
\Log::debug("Exception was: ".$e->getMessage());
|
Log::debug("Exception was: ".$e->getMessage());
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
//return response()->json(['message' => $e->getMessage()], 500);
|
//return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Connection failed but we cannot debug it any further on our end.');
|
Log::debug('Connection failed but we cannot debug it any further on our end.');
|
||||||
return response()->json(['message' => $e->getMessage()], 500);
|
return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ldaptestlogin(Request $request)
|
public function ldaptestlogin(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Setting::getSettings()->ldap_enabled != '1') {
|
if (Setting::getSettings()->ldap_enabled != '1') {
|
||||||
\Log::debug('LDAP is not enabled. Cannot test.');
|
Log::debug('LDAP is not enabled. Cannot test.');
|
||||||
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,39 +100,39 @@ class SettingsController extends Controller
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules);
|
$validator = Validator::make($request->all(), $rules);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
\Log::debug('LDAP Validation test failed.');
|
Log::debug('LDAP Validation test failed.');
|
||||||
$validation_errors = implode(' ',$validator->errors()->all());
|
$validation_errors = implode(' ',$validator->errors()->all());
|
||||||
return response()->json(['message' => $validator->errors()->all()], 400);
|
return response()->json(['message' => $validator->errors()->all()], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\Log::debug('Preparing to test LDAP login');
|
Log::debug('Preparing to test LDAP login');
|
||||||
try {
|
try {
|
||||||
$connection = Ldap::connectToLdap();
|
$connection = Ldap::connectToLdap();
|
||||||
try {
|
try {
|
||||||
Ldap::bindAdminToLdap($connection);
|
Ldap::bindAdminToLdap($connection);
|
||||||
\Log::debug('Attempting to bind to LDAP for LDAP test');
|
Log::debug('Attempting to bind to LDAP for LDAP test');
|
||||||
try {
|
try {
|
||||||
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
|
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
|
||||||
if ($ldap_user) {
|
if ($ldap_user) {
|
||||||
\Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
|
Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
|
||||||
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
|
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
|
||||||
}
|
}
|
||||||
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
|
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('LDAP login failed');
|
Log::debug('LDAP login failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Bind failed');
|
Log::debug('Bind failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 400);
|
return response()->json(['message' => $e->getMessage()], 400);
|
||||||
//return response()->json(['message' => $e->getMessage()], 500);
|
//return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('Connection failed');
|
Log::debug('Connection failed');
|
||||||
return response()->json(['message' => $e->getMessage()], 500);
|
return response()->json(['message' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +144,8 @@ class SettingsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function ajaxTestEmail()
|
public function ajaxTestEmail() : JsonResponse
|
||||||
{
|
{
|
||||||
if (!config('app.lock_passwords')) {
|
if (!config('app.lock_passwords')) {
|
||||||
try {
|
try {
|
||||||
|
@ -170,9 +165,8 @@ class SettingsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function purgeBarcodes()
|
public function purgeBarcodes() : JsonResponse
|
||||||
{
|
{
|
||||||
$file_count = 0;
|
$file_count = 0;
|
||||||
$files = Storage::disk('public')->files('barcodes');
|
$files = Storage::disk('public')->files('barcodes');
|
||||||
|
@ -181,19 +175,19 @@ class SettingsController extends Controller
|
||||||
|
|
||||||
$file_parts = explode('.', $file);
|
$file_parts = explode('.', $file);
|
||||||
$extension = end($file_parts);
|
$extension = end($file_parts);
|
||||||
\Log::debug($extension);
|
Log::debug($extension);
|
||||||
|
|
||||||
// Only generated barcodes would have a .png file extension
|
// Only generated barcodes would have a .png file extension
|
||||||
if ($extension == 'png') {
|
if ($extension == 'png') {
|
||||||
\Log::debug('Deleting: '.$file);
|
Log::debug('Deleting: '.$file);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete($file);
|
Storage::disk('public')->delete($file);
|
||||||
\Log::debug('Deleting: '.$file);
|
Log::debug('Deleting: '.$file);
|
||||||
$file_count++;
|
$file_count++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,9 +205,8 @@ class SettingsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return array | JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function showLoginAttempts(Request $request)
|
public function showLoginAttempts(Request $request) : array
|
||||||
{
|
{
|
||||||
$allowed_columns = ['id', 'username', 'remote_ip', 'user_agent', 'successful', 'created_at'];
|
$allowed_columns = ['id', 'username', 'remote_ip', 'user_agent', 'successful', 'created_at'];
|
||||||
|
|
||||||
|
@ -233,9 +226,9 @@ class SettingsController extends Controller
|
||||||
* Lists backup files
|
* Lists backup files
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto]
|
* @author [A. Gianotto]
|
||||||
* @return array | JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function listBackups() {
|
public function listBackups() : array
|
||||||
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$path = 'app/backups';
|
$path = 'app/backups';
|
||||||
$backup_files = Storage::files($path);
|
$backup_files = Storage::files($path);
|
||||||
|
@ -276,9 +269,9 @@ class SettingsController extends Controller
|
||||||
* exhausts memory on larger files.
|
* exhausts memory on larger files.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto]
|
* @author [A. Gianotto]
|
||||||
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
||||||
*/
|
*/
|
||||||
public function downloadBackup($file) {
|
public function downloadBackup($file) : JsonResponse | BinaryFileResponse
|
||||||
|
{
|
||||||
|
|
||||||
$path = storage_path('app/backups');
|
$path = storage_path('app/backups');
|
||||||
|
|
||||||
|
@ -296,9 +289,9 @@ class SettingsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto]
|
* @author [A. Gianotto]
|
||||||
* @since [v6.3.1]
|
* @since [v6.3.1]
|
||||||
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
||||||
*/
|
*/
|
||||||
public function downloadLatestBackup() {
|
public function downloadLatestBackup() : JsonResponse | BinaryFileResponse
|
||||||
|
{
|
||||||
|
|
||||||
$fileData = collect();
|
$fileData = collect();
|
||||||
foreach (Storage::files('app/backups') as $file) {
|
foreach (Storage::files('app/backups') as $file) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use App\Models\Asset;
|
||||||
use App\Models\Statuslabel;
|
use App\Models\Statuslabel;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Transformers\PieChartTransformer;
|
use App\Http\Transformers\PieChartTransformer;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class StatuslabelsController extends Controller
|
class StatuslabelsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -20,9 +20,8 @@ class StatuslabelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Statuslabel::class);
|
$this->authorize('view', Statuslabel::class);
|
||||||
$allowed_columns = ['id', 'name', 'created_at', 'assets_count', 'color', 'notes', 'default_label'];
|
$allowed_columns = ['id', 'name', 'created_at', 'assets_count', 'color', 'notes', 'default_label'];
|
||||||
|
@ -72,9 +71,8 @@ class StatuslabelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Statuslabel::class);
|
$this->authorize('create', Statuslabel::class);
|
||||||
$request->except('deployable', 'pending', 'archived');
|
$request->except('deployable', 'pending', 'archived');
|
||||||
|
@ -108,9 +106,8 @@ class StatuslabelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Statuslabel::class);
|
$this->authorize('view', Statuslabel::class);
|
||||||
$statuslabel = Statuslabel::findOrFail($id);
|
$statuslabel = Statuslabel::findOrFail($id);
|
||||||
|
@ -126,9 +123,8 @@ class StatuslabelsController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Statuslabel::class);
|
$this->authorize('update', Statuslabel::class);
|
||||||
$statuslabel = Statuslabel::findOrFail($id);
|
$statuslabel = Statuslabel::findOrFail($id);
|
||||||
|
@ -163,9 +159,8 @@ class StatuslabelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Statuslabel::class);
|
$this->authorize('delete', Statuslabel::class);
|
||||||
$statuslabel = Statuslabel::findOrFail($id);
|
$statuslabel = Statuslabel::findOrFail($id);
|
||||||
|
@ -188,9 +183,8 @@ class StatuslabelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getAssetCountByStatuslabel()
|
public function getAssetCountByStatuslabel() : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Statuslabel::class);
|
$this->authorize('view', Statuslabel::class);
|
||||||
$statuslabels = Statuslabel::withCount('assets')->get();
|
$statuslabels = Statuslabel::withCount('assets')->get();
|
||||||
|
@ -215,9 +209,8 @@ class StatuslabelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v6.0.11]
|
* @since [v6.0.11]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getAssetCountByMetaStatus()
|
public function getAssetCountByMetaStatus() : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Statuslabel::class);
|
$this->authorize('view', Statuslabel::class);
|
||||||
|
|
||||||
|
@ -245,9 +238,8 @@ class StatuslabelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function assets(Request $request, $id)
|
public function assets(Request $request, $id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Statuslabel::class);
|
$this->authorize('view', Statuslabel::class);
|
||||||
$this->authorize('index', Asset::class);
|
$this->authorize('index', Asset::class);
|
||||||
|
@ -281,9 +273,8 @@ class StatuslabelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function checkIfDeployable($id)
|
public function checkIfDeployable($id) : string
|
||||||
{
|
{
|
||||||
$statuslabel = Statuslabel::findOrFail($id);
|
$statuslabel = Statuslabel::findOrFail($id);
|
||||||
if ($statuslabel->getStatuslabelType() == 'deployable') {
|
if ($statuslabel->getStatuslabelType() == 'deployable') {
|
||||||
|
@ -300,7 +291,7 @@ class StatuslabelsController extends Controller
|
||||||
* @since [v6.1.1]
|
* @since [v6.1.1]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
|
|
|
@ -10,6 +10,7 @@ use App\Models\Supplier;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class SuppliersController extends Controller
|
class SuppliersController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -20,7 +21,7 @@ class SuppliersController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request): array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Supplier::class);
|
$this->authorize('view', Supplier::class);
|
||||||
$allowed_columns = ['
|
$allowed_columns = ['
|
||||||
|
@ -114,9 +115,8 @@ class SuppliersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Supplier::class);
|
$this->authorize('create', Supplier::class);
|
||||||
$supplier = new Supplier;
|
$supplier = new Supplier;
|
||||||
|
@ -136,9 +136,8 @@ class SuppliersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', Supplier::class);
|
$this->authorize('view', Supplier::class);
|
||||||
$supplier = Supplier::findOrFail($id);
|
$supplier = Supplier::findOrFail($id);
|
||||||
|
@ -154,9 +153,8 @@ class SuppliersController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id)
|
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Supplier::class);
|
$this->authorize('update', Supplier::class);
|
||||||
$supplier = Supplier::findOrFail($id);
|
$supplier = Supplier::findOrFail($id);
|
||||||
|
@ -176,9 +174,8 @@ class SuppliersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Supplier::class);
|
$this->authorize('delete', Supplier::class);
|
||||||
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
|
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
|
||||||
|
@ -209,7 +206,7 @@ class SuppliersController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('view.selectlists');
|
$this->authorize('view.selectlists');
|
||||||
|
|
|
@ -13,15 +13,18 @@ use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Http\Transformers\UsersTransformer;
|
use App\Http\Transformers\UsersTransformer;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Consumable;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\CurrentInventory;
|
use App\Notifications\CurrentInventory;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Http\Requests\DeleteUserRequest;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class UsersController extends Controller
|
class UsersController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -31,9 +34,9 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
|
|
||||||
|
@ -75,10 +78,14 @@ class UsersController extends Controller
|
||||||
'users.autoassign_licenses',
|
'users.autoassign_licenses',
|
||||||
'users.website',
|
'users.website',
|
||||||
|
|
||||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
|
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations')
|
||||||
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
|
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count');
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->filled('search') != '') {
|
||||||
|
$users = $users->TextSearch($request->input('search'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('activated')) {
|
if ($request->filled('activated')) {
|
||||||
$users = $users->where('users.activated', '=', $request->input('activated'));
|
$users = $users->where('users.activated', '=', $request->input('activated'));
|
||||||
}
|
}
|
||||||
|
@ -187,12 +194,23 @@ class UsersController extends Controller
|
||||||
$users->has('accessories', '=', $request->input('accessories_count'));
|
$users->has('accessories', '=', $request->input('accessories_count'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manages_users_count')) {
|
||||||
|
$users->has('manages_users_count', '=', $request->input('manages_users_count'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manages_locations_count')) {
|
||||||
|
$users->has('manages_locations_count', '=', $request->input('manages_locations_count'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('autoassign_licenses')) {
|
if ($request->filled('autoassign_licenses')) {
|
||||||
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
|
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
|
||||||
$users = $users->TextSearch($request->input('search'));
|
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
|
||||||
|
$users = $users->onlyTrashed();
|
||||||
|
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
|
||||||
|
$users = $users->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
|
@ -230,10 +248,6 @@ class UsersController extends Controller
|
||||||
'jobtitle',
|
'jobtitle',
|
||||||
'username',
|
'username',
|
||||||
'employee_num',
|
'employee_num',
|
||||||
'assets',
|
|
||||||
'accessories',
|
|
||||||
'consumables',
|
|
||||||
'licenses',
|
|
||||||
'groups',
|
'groups',
|
||||||
'activated',
|
'activated',
|
||||||
'created_at',
|
'created_at',
|
||||||
|
@ -244,6 +258,8 @@ class UsersController extends Controller
|
||||||
'licenses_count',
|
'licenses_count',
|
||||||
'consumables_count',
|
'consumables_count',
|
||||||
'accessories_count',
|
'accessories_count',
|
||||||
|
'manages_users_count',
|
||||||
|
'manages_locations_count',
|
||||||
'phone',
|
'phone',
|
||||||
'address',
|
'address',
|
||||||
'city',
|
'city',
|
||||||
|
@ -262,18 +278,11 @@ class UsersController extends Controller
|
||||||
'website',
|
'website',
|
||||||
];
|
];
|
||||||
|
|
||||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name';
|
||||||
$users = $users->orderBy($sort, $order);
|
$users = $users->orderBy($sort, $order);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($request->filled('deleted')) && ($request->input('deleted') == 'true')) {
|
|
||||||
$users = $users->onlyTrashed();
|
|
||||||
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
|
|
||||||
$users = $users->withTrashed();
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = Company::scopeCompanyables($users);
|
|
||||||
|
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
|
@ -293,7 +302,7 @@ class UsersController extends Controller
|
||||||
* @since [v4.0.16]
|
* @since [v4.0.16]
|
||||||
* @see \App\Http\Transformers\SelectlistTransformer
|
* @see \App\Http\Transformers\SelectlistTransformer
|
||||||
*/
|
*/
|
||||||
public function selectlist(Request $request)
|
public function selectlist(Request $request) : array
|
||||||
{
|
{
|
||||||
$users = User::select(
|
$users = User::select(
|
||||||
[
|
[
|
||||||
|
@ -308,8 +317,6 @@ class UsersController extends Controller
|
||||||
]
|
]
|
||||||
)->where('show_in_list', '=', '1');
|
)->where('show_in_list', '=', '1');
|
||||||
|
|
||||||
$users = Company::scopeCompanyables($users);
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$users = $users->where(function ($query) use ($request) {
|
$users = $users->where(function ($query) use ($request) {
|
||||||
$query->SimpleNameSearch($request->get('search'))
|
$query->SimpleNameSearch($request->get('search'))
|
||||||
|
@ -351,21 +358,20 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(SaveUserRequest $request)
|
public function store(SaveUserRequest $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', User::class);
|
$this->authorize('create', User::class);
|
||||||
|
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->fill($request->all());
|
$user->fill($request->all());
|
||||||
$user->created_by = Auth::user()->id;
|
$user->created_by = auth()->id();
|
||||||
|
|
||||||
if ($request->has('permissions')) {
|
if ($request->has('permissions')) {
|
||||||
$permissions_array = $request->input('permissions');
|
$permissions_array = $request->input('permissions');
|
||||||
|
|
||||||
// Strip out the superuser permission if the API user isn't a superadmin
|
// Strip out the superuser permission if the API user isn't a superadmin
|
||||||
if (! Auth::user()->isSuperUser()) {
|
if (! auth()->user()->isSuperUser()) {
|
||||||
unset($permissions_array['superuser']);
|
unset($permissions_array['superuser']);
|
||||||
}
|
}
|
||||||
$user->permissions = $permissions_array;
|
$user->permissions = $permissions_array;
|
||||||
|
@ -398,14 +404,18 @@ class UsersController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count')->findOrFail($id);
|
|
||||||
|
|
||||||
return (new UsersTransformer)->transformUser($user);
|
if ($user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count')->find($id)) {
|
||||||
|
$this->authorize('view', $user);
|
||||||
|
return (new UsersTransformer)->transformUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -416,89 +426,88 @@ class UsersController extends Controller
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function update(SaveUserRequest $request, $id)
|
public function update(SaveUserRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', User::class);
|
$this->authorize('update', User::class);
|
||||||
|
|
||||||
$user = User::findOrFail($id);
|
if ($user = User::find($id)) {
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
|
||||||
*
|
|
||||||
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
|
||||||
*
|
|
||||||
* Thanks, jerks. You are why we can't have nice things. - snipe
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
|
$this->authorize('update', $user);
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
|
||||||
}
|
/**
|
||||||
|
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
||||||
|
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
||||||
|
* Thanks, jerks. You are why we can't have nice things. - snipe
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
$user->fill($request->all());
|
if ((($id == 1) || ($id == 2)) && (config('app.lock_passwords'))) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
||||||
if ($user->id == $request->input('manager_id')) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->filled('password')) {
|
|
||||||
$user->password = bcrypt($request->input('password'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to use has() instead of filled()
|
|
||||||
// here because we need to overwrite permissions
|
|
||||||
// if someone needs to null them out
|
|
||||||
if ($request->has('permissions')) {
|
|
||||||
$permissions_array = $request->input('permissions');
|
|
||||||
|
|
||||||
// Strip out the superuser permission if the API user isn't a superadmin
|
|
||||||
if (! Auth::user()->isSuperUser()) {
|
|
||||||
unset($permissions_array['superuser']);
|
|
||||||
}
|
}
|
||||||
$user->permissions = $permissions_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
$user->fill($request->all());
|
||||||
|
|
||||||
// Update the location of any assets checked out to this user
|
if ($user->id == $request->input('manager_id')) {
|
||||||
Asset::where('assigned_type', User::class)
|
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
||||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
}
|
||||||
|
|
||||||
|
if ($request->filled('password')) {
|
||||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
$user->password = bcrypt($request->input('password'));
|
||||||
|
}
|
||||||
if ($user->save()) {
|
|
||||||
|
|
||||||
// Sync group memberships:
|
// We need to use has() instead of filled()
|
||||||
// This was changed in Snipe-IT v4.6.x to 4.7, since we upgraded to Laravel 5.5
|
// here because we need to overwrite permissions
|
||||||
// which changes the behavior of has vs filled.
|
// if someone needs to null them out
|
||||||
// The $request->has method will now return true even if the input value is an empty string or null.
|
if ($request->has('permissions')) {
|
||||||
// A new $request->filled method has was added that provides the previous behavior of the has method.
|
$permissions_array = $request->input('permissions');
|
||||||
|
|
||||||
// Check if the request has groups passed and has a value
|
// Strip out the individual superuser permission if the API user isn't a superadmin
|
||||||
if ($request->filled('groups')) {
|
if (!auth()->user()->isSuperUser()) {
|
||||||
$validator = Validator::make($request->all(), [
|
unset($permissions_array['superuser']);
|
||||||
'groups.*' => 'integer|exists:permission_groups,id',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails()){
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
|
||||||
}
|
}
|
||||||
$user->groups()->sync($request->input('groups'));
|
|
||||||
// The groups field has been passed but it is null, so we should blank it out
|
$user->permissions = $permissions_array;
|
||||||
} elseif ($request->has('groups')) {
|
|
||||||
$user->groups()->sync([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
// Update the location of any assets checked out to this user
|
||||||
|
Asset::where('assigned_type', User::class)
|
||||||
|
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||||
|
|
||||||
|
|
||||||
|
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||||
|
|
||||||
|
if ($user->save()) {
|
||||||
|
|
||||||
|
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||||
|
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
|
||||||
|
|
||||||
|
$validator = Validator::make($request->only('groups'), [
|
||||||
|
'groups.*' => 'integer|exists:permission_groups,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync the groups since the user is a superuser and the groups pass validation
|
||||||
|
$user->groups()->sync($request->input('groups'));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -507,45 +516,35 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy(DeleteUserRequest $request, $id) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', User::class);
|
$this->authorize('delete', User::class);
|
||||||
$user = User::findOrFail($id);
|
|
||||||
$this->authorize('delete', $user);
|
|
||||||
|
|
||||||
if (($user->assets) && ($user->assets->count() > 0)) {
|
if ($user = User::withTrashed()->find($id)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->licenses) && ($user->licenses->count() > 0)) {
|
$this->authorize('delete', $user);
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->licenses->count().' license(s) associated with them and cannot be deleted.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->accessories) && ($user->accessories->count() > 0)) {
|
if ($user->delete()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->accessories->count().' accessories associated with them.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) {
|
// Remove the user's avatar if they have one
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has '.$user->managedLocations()->count().' locations that they manage.'));
|
if (Storage::disk('public')->exists('avatars/' . $user->avatar)) {
|
||||||
}
|
try {
|
||||||
|
Storage::disk('public')->delete('avatars/' . $user->avatar);
|
||||||
if ($user->delete()) {
|
} catch (\Exception $e) {
|
||||||
|
Log::debug($e);
|
||||||
// Remove the user's avatar if they have one
|
}
|
||||||
if (Storage::disk('public')->exists('avatars/'.$user->avatar)) {
|
|
||||||
try {
|
|
||||||
Storage::disk('public')->delete('avatars/'.$user->avatar);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -554,34 +553,41 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function assets(Request $request, $id)
|
public function assets(Request $request, $id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model');
|
|
||||||
|
if ($user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($id)) {
|
||||||
|
$this->authorize('view', $user);
|
||||||
|
|
||||||
|
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model');
|
||||||
|
|
||||||
|
|
||||||
// Filter on category ID
|
// Filter on category ID
|
||||||
if ($request->filled('category_id')) {
|
if ($request->filled('category_id')) {
|
||||||
$assets = $assets->InCategory($request->input('category_id'));
|
$assets = $assets->InCategory($request->input('category_id'));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Filter on model ID
|
|
||||||
if ($request->filled('model_id')) {
|
|
||||||
|
|
||||||
$model_ids = $request->input('model_id');
|
|
||||||
if (!is_array($model_ids)) {
|
|
||||||
$model_ids = array($model_ids);
|
|
||||||
}
|
}
|
||||||
$assets = $assets->InModelList($model_ids);
|
|
||||||
|
|
||||||
|
// Filter on model ID
|
||||||
|
if ($request->filled('model_id')) {
|
||||||
|
|
||||||
|
$model_ids = $request->input('model_id');
|
||||||
|
if (!is_array($model_ids)) {
|
||||||
|
$model_ids = array($model_ids);
|
||||||
|
}
|
||||||
|
$assets = $assets->InModelList($model_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$assets = $assets->get();
|
||||||
|
|
||||||
|
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
$assets = $assets->get();
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -591,19 +597,26 @@ class UsersController extends Controller
|
||||||
* @since [v6.0.13]
|
* @since [v6.0.13]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function emailAssetList(Request $request, $id)
|
public function emailAssetList(Request $request, $id) : JsonResponse
|
||||||
{
|
|
||||||
$user = User::findOrFail($id);
|
|
||||||
|
|
||||||
if (empty($user->email)) {
|
{
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
|
$this->authorize('update', User::class);
|
||||||
|
|
||||||
|
if ($user = User::find($id)) {
|
||||||
|
$this->authorize('update', $user);
|
||||||
|
|
||||||
|
if (empty($user->email)) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->notify((new CurrentInventory($user)));
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->notify((new CurrentInventory($user)));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -612,13 +625,13 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function consumables(Request $request, $id)
|
public function consumables(Request $request, $id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$this->authorize('view', Consumable::class);
|
$this->authorize('view', Consumable::class);
|
||||||
$user = User::findOrFail($id);
|
$user = User::findOrFail($id);
|
||||||
|
$this->authorize('view', $user);
|
||||||
$consumables = $user->consumables;
|
$consumables = $user->consumables;
|
||||||
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
|
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
|
||||||
}
|
}
|
||||||
|
@ -629,12 +642,12 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.6.14]
|
* @since [v4.6.14]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function accessories($id)
|
public function accessories($id) : array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$user = User::findOrFail($id);
|
$user = User::findOrFail($id);
|
||||||
|
$this->authorize('view', $user);
|
||||||
$this->authorize('view', Accessory::class);
|
$this->authorize('view', Accessory::class);
|
||||||
$accessories = $user->accessories;
|
$accessories = $user->accessories;
|
||||||
|
|
||||||
|
@ -647,14 +660,14 @@ class UsersController extends Controller
|
||||||
* @author [N. Mathar] [<snipe@snipe.net>]
|
* @author [N. Mathar] [<snipe@snipe.net>]
|
||||||
* @since [v5.0]
|
* @since [v5.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function licenses($id)
|
public function licenses($id) : JsonResponse | array
|
||||||
{
|
{
|
||||||
$this->authorize('view', User::class);
|
$this->authorize('view', User::class);
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
|
||||||
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
||||||
|
$this->authorize('update', $user);
|
||||||
$licenses = $user->licenses()->get();
|
$licenses = $user->licenses()->get();
|
||||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||||
}
|
}
|
||||||
|
@ -669,15 +682,15 @@ class UsersController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string JSON
|
|
||||||
*/
|
*/
|
||||||
public function postTwoFactorReset(Request $request)
|
public function postTwoFactorReset(Request $request) : JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', User::class);
|
$this->authorize('update', User::class);
|
||||||
|
|
||||||
if ($request->filled('id')) {
|
if ($request->filled('id')) {
|
||||||
try {
|
try {
|
||||||
$user = User::find($request->get('id'));
|
$user = User::find($request->get('id'));
|
||||||
|
$this->authorize('update', $user);
|
||||||
$user->two_factor_secret = null;
|
$user->two_factor_secret = null;
|
||||||
$user->two_factor_enrolled = 0;
|
$user->two_factor_enrolled = 0;
|
||||||
$user->saveQuietly();
|
$user->saveQuietly();
|
||||||
|
@ -689,7 +702,7 @@ class UsersController extends Controller
|
||||||
$logaction->item_type = User::class;
|
$logaction->item_type = User::class;
|
||||||
$logaction->item_id = $user->id;
|
$logaction->item_id = $user->id;
|
||||||
$logaction->created_at = date('Y-m-d H:i:s');
|
$logaction->created_at = date('Y-m-d H:i:s');
|
||||||
$logaction->user_id = Auth::user()->id;
|
$logaction->user_id = auth()->id();
|
||||||
$logaction->logaction('2FA reset');
|
$logaction->logaction('2FA reset');
|
||||||
|
|
||||||
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
|
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
|
||||||
|
@ -708,9 +721,8 @@ class UsersController extends Controller
|
||||||
* @author [Juan Font] [<juanfontalonso@gmail.com>]
|
* @author [Juan Font] [<juanfontalonso@gmail.com>]
|
||||||
* @since [v4.4.2]
|
* @since [v4.4.2]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function getCurrentUserInfo(Request $request)
|
public function getCurrentUserInfo(Request $request) : array
|
||||||
{
|
{
|
||||||
return (new UsersTransformer)->transformUser($request->user());
|
return (new UsersTransformer)->transformUser($request->user());
|
||||||
}
|
}
|
||||||
|
@ -721,12 +733,13 @@ class UsersController extends Controller
|
||||||
* @author [E. Taylor] [<dev@evantaylor.name>]
|
* @author [E. Taylor] [<dev@evantaylor.name>]
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @since [v6.0.0]
|
* @since [v6.0.0]
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function restore($userId = null)
|
public function restore($userId) : JsonResponse
|
||||||
{
|
{
|
||||||
|
$this->authorize('delete', User::class);
|
||||||
|
|
||||||
if ($user = User::withTrashed()->find($userId)) {
|
if ($user = User::withTrashed()->find($userId)) {
|
||||||
|
|
||||||
$this->authorize('delete', $user);
|
$this->authorize('delete', $user);
|
||||||
|
|
||||||
if ($user->deleted_at == '') {
|
if ($user->deleted_at == '') {
|
||||||
|
@ -739,14 +752,12 @@ class UsersController extends Controller
|
||||||
$logaction->item_type = User::class;
|
$logaction->item_type = User::class;
|
||||||
$logaction->item_id = $user->id;
|
$logaction->item_id = $user->id;
|
||||||
$logaction->created_at = date('Y-m-d H:i:s');
|
$logaction->created_at = date('Y-m-d H:i:s');
|
||||||
$logaction->user_id = Auth::user()->id;
|
$logaction->user_id = auth()->id();
|
||||||
$logaction->logaction('restore');
|
$logaction->logaction('restore');
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check validation to make sure we're not restoring a user with the same username as an existing user
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200);
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200);
|
||||||
|
|
|
@ -2,17 +2,14 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetMaintenance;
|
use App\Models\AssetMaintenance;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Slack;
|
use \Illuminate\Contracts\View\View;
|
||||||
use Str;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
use TCPDF;
|
|
||||||
use View;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Asset Maintenance for
|
* This controller handles all actions related to Asset Maintenance for
|
||||||
|
@ -29,9 +26,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
private static function getInsufficientPermissionsRedirect()
|
private static function getInsufficientPermissionsRedirect(): RedirectResponse
|
||||||
{
|
{
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')
|
||||||
->with('error', trans('general.insufficient_permissions'));
|
->with('error', trans('general.insufficient_permissions'));
|
||||||
|
@ -46,9 +42,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
return view('asset_maintenances/index');
|
return view('asset_maintenances/index');
|
||||||
|
@ -63,7 +58,7 @@ class AssetMaintenancesController extends Controller
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create() : View
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
$asset = null;
|
$asset = null;
|
||||||
|
@ -92,9 +87,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// create a new model instance
|
// create a new model instance
|
||||||
|
@ -144,9 +138,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function edit($assetMaintenanceId = null)
|
public function edit($assetMaintenanceId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
|
@ -162,14 +155,9 @@ class AssetMaintenancesController extends Controller
|
||||||
return static::getInsufficientPermissionsRedirect();
|
return static::getInsufficientPermissionsRedirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prepare Improvement Type List
|
// Prepare Improvement Type List
|
||||||
$assetMaintenanceType = [
|
$assetMaintenanceType = ['' => 'Select an improvement type'] + AssetMaintenance::getImprovementOptions();
|
||||||
'' => 'Select an improvement type',
|
|
||||||
] + AssetMaintenance::getImprovementOptions();
|
|
||||||
|
|
||||||
// Get Supplier List
|
|
||||||
// Render the view
|
|
||||||
return view('asset_maintenances/edit')
|
return view('asset_maintenances/edit')
|
||||||
->with('selectedAsset', null)
|
->with('selectedAsset', null)
|
||||||
->with('assetMaintenanceType', $assetMaintenanceType)
|
->with('assetMaintenanceType', $assetMaintenanceType)
|
||||||
|
@ -183,11 +171,10 @@ class AssetMaintenancesController extends Controller
|
||||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @return mixed
|
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $assetMaintenanceId = null)
|
public function update(Request $request, $assetMaintenanceId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
|
@ -255,9 +242,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function destroy($assetMaintenanceId)
|
public function destroy($assetMaintenanceId) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
|
@ -284,9 +270,8 @@ class AssetMaintenancesController extends Controller
|
||||||
* @param int $assetMaintenanceId
|
* @param int $assetMaintenanceId
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function show($assetMaintenanceId)
|
public function show($assetMaintenanceId) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,21 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
use App\Http\Requests\StoreAssetModelRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
|
use App\Models\SnipeModel;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Input;
|
|
||||||
use Illuminate\Support\Facades\View;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Redirect;
|
use Illuminate\Http\Request;
|
||||||
use Request;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Storage;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to asset models for
|
* This class controls all actions related to asset models for
|
||||||
|
@ -34,10 +35,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$this->authorize('index', AssetModel::class);
|
$this->authorize('index', AssetModel::class);
|
||||||
|
|
||||||
|
@ -49,10 +48,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create() : View
|
||||||
{
|
{
|
||||||
$this->authorize('create', AssetModel::class);
|
$this->authorize('create', AssetModel::class);
|
||||||
|
|
||||||
|
@ -67,16 +64,12 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreAssetModelRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', AssetModel::class);
|
$this->authorize('create', AssetModel::class);
|
||||||
// Create a new asset model
|
|
||||||
$model = new AssetModel;
|
$model = new AssetModel;
|
||||||
|
|
||||||
// Save the model data
|
|
||||||
$model->eol = $request->input('eol');
|
$model->eol = $request->input('eol');
|
||||||
$model->depreciation_id = $request->input('depreciation_id');
|
$model->depreciation_id = $request->input('depreciation_id');
|
||||||
$model->name = $request->input('name');
|
$model->name = $request->input('name');
|
||||||
|
@ -86,7 +79,7 @@ class AssetModelsController extends Controller
|
||||||
$model->category_id = $request->input('category_id');
|
$model->category_id = $request->input('category_id');
|
||||||
$model->notes = $request->input('notes');
|
$model->notes = $request->input('notes');
|
||||||
$model->user_id = Auth::id();
|
$model->user_id = Auth::id();
|
||||||
$model->requestable = Request::has('requestable');
|
$model->requestable = $request->has('requestable');
|
||||||
|
|
||||||
if ($request->input('fieldset_id') != '') {
|
if ($request->input('fieldset_id') != '') {
|
||||||
$model->fieldset_id = $request->input('fieldset_id');
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
|
@ -94,7 +87,6 @@ class AssetModelsController extends Controller
|
||||||
|
|
||||||
$model = $request->handleImages($model);
|
$model = $request->handleImages($model);
|
||||||
|
|
||||||
// Was it created?
|
|
||||||
if ($model->save()) {
|
if ($model->save()) {
|
||||||
if ($this->shouldAddDefaultValues($request->input())) {
|
if ($this->shouldAddDefaultValues($request->input())) {
|
||||||
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
||||||
|
@ -114,18 +106,14 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit($modelId = null)
|
public function edit($modelId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', AssetModel::class);
|
$this->authorize('update', AssetModel::class);
|
||||||
if ($item = AssetModel::find($modelId)) {
|
if ($item = AssetModel::find($modelId)) {
|
||||||
$category_type = 'asset';
|
$category_type = 'asset';
|
||||||
$view = View::make('models/edit', compact('item', 'category_type'));
|
return view('models/edit', compact('item', 'category_type'))->with('depreciation_list', Helper::depreciationList());
|
||||||
$view->with('depreciation_list', Helper::depreciationList());
|
|
||||||
|
|
||||||
return $view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
|
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
|
||||||
|
@ -140,15 +128,14 @@ class AssetModelsController extends Controller
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $modelId = null)
|
public function update(StoreAssetModelRequest $request, $modelId) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', AssetModel::class);
|
$this->authorize('update', AssetModel::class);
|
||||||
// Check if the model exists
|
|
||||||
if (is_null($model = AssetModel::find($modelId))) {
|
if (is_null($model = AssetModel::find($modelId))) {
|
||||||
// Redirect to the models management page
|
|
||||||
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
|
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +161,6 @@ class AssetModelsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($model->save()) {
|
if ($model->save()) {
|
||||||
if ($model->wasChanged('eol')) {
|
if ($model->wasChanged('eol')) {
|
||||||
if ($model->eol > 0) {
|
if ($model->eol > 0) {
|
||||||
|
@ -201,10 +185,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($modelId)
|
public function destroy($modelId) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', AssetModel::class);
|
$this->authorize('delete', AssetModel::class);
|
||||||
// Check if the model exists
|
// Check if the model exists
|
||||||
|
@ -221,7 +203,7 @@ class AssetModelsController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('models/'.$model->image);
|
Storage::disk('public')->delete('models/'.$model->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::info($e);
|
Log::info($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,10 +220,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function getRestore($id)
|
public function getRestore($id) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', AssetModel::class);
|
$this->authorize('create', AssetModel::class);
|
||||||
|
|
||||||
|
@ -256,7 +236,7 @@ class AssetModelsController extends Controller
|
||||||
$logaction->item_type = User::class;
|
$logaction->item_type = User::class;
|
||||||
$logaction->item_id = $model->id;
|
$logaction->item_id = $model->id;
|
||||||
$logaction->created_at = date('Y-m-d H:i:s');
|
$logaction->created_at = date('Y-m-d H:i:s');
|
||||||
$logaction->user_id = Auth::user()->id;
|
$logaction->user_id = auth()->id();
|
||||||
$logaction->logaction('restore');
|
$logaction->logaction('restore');
|
||||||
|
|
||||||
|
|
||||||
|
@ -283,13 +263,11 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show($modelId = null)
|
public function show($modelId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', AssetModel::class);
|
$this->authorize('view', AssetModel::class);
|
||||||
$model = AssetModel::withTrashed()->withCount('assets')->find($modelId);
|
$model = AssetModel::withTrashed()->find($modelId);
|
||||||
|
|
||||||
if (isset($model->id)) {
|
if (isset($model->id)) {
|
||||||
return view('models/view', compact('model'));
|
return view('models/view', compact('model'));
|
||||||
|
@ -304,9 +282,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function getClone($modelId = null)
|
public function getClone($modelId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', AssetModel::class);
|
$this->authorize('create', AssetModel::class);
|
||||||
// Check if the model exists
|
// Check if the model exists
|
||||||
|
@ -332,9 +309,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [B. Wetherington] [<uberbrady@gmail.com>]
|
* @author [B. Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function getCustomFields($modelId)
|
public function getCustomFields($modelId) : View
|
||||||
{
|
{
|
||||||
return view('models.custom_fields_form')->with('model', AssetModel::find($modelId));
|
return view('models.custom_fields_form')->with('model', AssetModel::find($modelId));
|
||||||
}
|
}
|
||||||
|
@ -346,9 +322,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.7]
|
* @since [v1.7]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
*/
|
||||||
public function postBulkEdit(Request $request)
|
public function postBulkEdit(Request $request) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$models_raw_array = $request->input('ids');
|
$models_raw_array = $request->input('ids');
|
||||||
|
|
||||||
|
@ -390,9 +365,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.7]
|
* @since [v1.7]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
*/
|
||||||
public function postBulkEditSave(Request $request)
|
public function postBulkEditSave(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$models_raw_array = $request->input('ids');
|
$models_raw_array = $request->input('ids');
|
||||||
$update_array = [];
|
$update_array = [];
|
||||||
|
@ -430,9 +404,8 @@ class AssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function postBulkDelete(Request $request)
|
public function postBulkDelete(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$models_raw_array = $request->input('ids');
|
$models_raw_array = $request->input('ids');
|
||||||
|
|
||||||
|
@ -471,9 +444,8 @@ class AssetModelsController extends Controller
|
||||||
* any default values were entered into the form.
|
* any default values were entered into the form.
|
||||||
*
|
*
|
||||||
* @param array $input
|
* @param array $input
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
private function shouldAddDefaultValues(array $input)
|
private function shouldAddDefaultValues(array $input) : bool
|
||||||
{
|
{
|
||||||
return ! empty($input['add_default_values'])
|
return ! empty($input['add_default_values'])
|
||||||
&& ! empty($input['default_values'])
|
&& ! empty($input['default_values'])
|
||||||
|
@ -485,9 +457,8 @@ class AssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @param AssetModel $model
|
* @param AssetModel $model
|
||||||
* @param array $defaultValues
|
* @param array $defaultValues
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues): bool
|
private function assignCustomFieldsDefaultValues(AssetModel|SnipeModel $model, array $defaultValues): bool
|
||||||
{
|
{
|
||||||
$data = array();
|
$data = array();
|
||||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||||
|
@ -496,17 +467,17 @@ class AssetModelsController extends Controller
|
||||||
$data[$customField->db_column] = $defaultValue;
|
$data[$customField->db_column] = $defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fieldsets = $model->fieldset->validation_rules();
|
$allRules = $model->fieldset->validation_rules();
|
||||||
$rules = array();
|
$rules = array();
|
||||||
|
|
||||||
foreach ($fieldsets as $fieldset => $validation){
|
foreach ($allRules as $field => $validation) {
|
||||||
// If the field is marked as required, eliminate the rule so it doesn't interfere with the default values
|
// If the field is marked as required, eliminate the rule so it doesn't interfere with the default values
|
||||||
// (we are at model level, the rule still applies when creating a new asset using this model)
|
// (we are at model level, the rule still applies when creating a new asset using this model)
|
||||||
$index = array_search('required', $validation);
|
$index = array_search('required', $validation);
|
||||||
if ($index !== false){
|
if ($index !== false){
|
||||||
$validation[$index] = 'nullable';
|
$validation[$index] = 'nullable';
|
||||||
}
|
}
|
||||||
$rules[$fieldset] = $validation;
|
$rules[$field] = $validation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$validator = Validator::make($data, $rules);
|
$validator = Validator::make($data, $rules);
|
||||||
|
@ -528,9 +499,8 @@ class AssetModelsController extends Controller
|
||||||
/**
|
/**
|
||||||
* Removes all default values
|
* Removes all default values
|
||||||
*
|
*
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
private function removeCustomFieldsDefaultValues(AssetModel $model)
|
private function removeCustomFieldsDefaultValues(AssetModel|SnipeModel $model): void
|
||||||
{
|
{
|
||||||
$model->defaultValues()->detach();
|
$model->defaultValues()->detach();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,11 @@ use App\Helpers\StorageHelper;
|
||||||
use App\Http\Requests\UploadFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use \Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
class AssetModelsFilesController extends Controller
|
class AssetModelsFilesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -16,12 +19,12 @@ class AssetModelsFilesController extends Controller
|
||||||
*
|
*
|
||||||
* @param UploadFileRequest $request
|
* @param UploadFileRequest $request
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*@since [v1.0]
|
*@since [v1.0]
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(UploadFileRequest $request, $modelId = null)
|
public function store(UploadFileRequest $request, $modelId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (! $model = AssetModel::find($modelId)) {
|
if (! $model = AssetModel::find($modelId)) {
|
||||||
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
@ -38,7 +41,7 @@ class AssetModelsFilesController extends Controller
|
||||||
|
|
||||||
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
|
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
|
||||||
|
|
||||||
$model->logUpload($file_name, e($request->get('notes')));
|
$model->logUpload($file_name, $request->get('notes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
||||||
|
@ -54,10 +57,8 @@ class AssetModelsFilesController extends Controller
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show($modelId = null, $fileId = null)
|
public function show($modelId = null, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
|
||||||
{
|
{
|
||||||
$model = AssetModel::find($modelId);
|
$model = AssetModel::find($modelId);
|
||||||
// the asset is valid
|
// the asset is valid
|
||||||
|
@ -70,8 +71,6 @@ class AssetModelsFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
$file = 'private_uploads/assetmodels/'.$log->filename;
|
||||||
\Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
|
|
||||||
if (! Storage::exists($file)) {
|
if (! Storage::exists($file)) {
|
||||||
return response('File '.$file.' not found on server', 404)
|
return response('File '.$file.' not found on server', 404)
|
||||||
|
@ -103,10 +102,8 @@ class AssetModelsFilesController extends Controller
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($modelId = null, $fileId = null)
|
public function destroy($modelId = null, $fileId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
$model = AssetModel::find($modelId);
|
$model = AssetModel::find($modelId);
|
||||||
$this->authorize('update', $model);
|
$this->authorize('update', $model);
|
||||||
|
|
|
@ -11,9 +11,10 @@ use App\Models\Asset;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Redirect;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\View;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class AssetCheckinController extends Controller
|
class AssetCheckinController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -25,11 +26,9 @@ class AssetCheckinController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function create($assetId, $backto = null)
|
public function create($assetId, $backto = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (is_null($asset = Asset::find($assetId))) {
|
if (is_null($asset = Asset::find($assetId))) {
|
||||||
|
@ -39,7 +38,17 @@ class AssetCheckinController extends Controller
|
||||||
|
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto);
|
// This asset is already checked in, redirect
|
||||||
|
|
||||||
|
if (is_null($asset->assignedTo)) {
|
||||||
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto)->with('table_name', 'Assets');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,11 +58,9 @@ class AssetCheckinController extends Controller
|
||||||
* @param AssetCheckinRequest $request
|
* @param AssetCheckinRequest $request
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @param null $backto
|
* @param null $backto
|
||||||
* @return Redirect
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function store(AssetCheckinRequest $request, $assetId = null, $backto = null)
|
public function store(AssetCheckinRequest $request, $assetId = null, $backto = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (is_null($asset = Asset::find($assetId))) {
|
if (is_null($asset = Asset::find($assetId))) {
|
||||||
|
@ -64,6 +71,11 @@ class AssetCheckinController extends Controller
|
||||||
if (is_null($target = $asset->assignedTo)) {
|
if (is_null($target = $asset->assignedTo)) {
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
if ($asset->assignedType() == Asset::USER) {
|
if ($asset->assignedType() == Asset::USER) {
|
||||||
|
@ -86,7 +98,7 @@ class AssetCheckinController extends Controller
|
||||||
$asset->location_id = $asset->rtd_location_id;
|
$asset->location_id = $asset->rtd_location_id;
|
||||||
|
|
||||||
if ($request->filled('location_id')) {
|
if ($request->filled('location_id')) {
|
||||||
\Log::debug('NEW Location ID: '.$request->get('location_id'));
|
Log::debug('NEW Location ID: '.$request->get('location_id'));
|
||||||
$asset->location_id = $request->get('location_id');
|
$asset->location_id = $request->get('location_id');
|
||||||
|
|
||||||
if ($request->get('update_default_location') == 0){
|
if ($request->get('update_default_location') == 0){
|
||||||
|
@ -116,15 +128,12 @@ class AssetCheckinController extends Controller
|
||||||
$acceptance->delete();
|
$acceptance->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Session::put('redirect_option', $request->get('redirect_option'));
|
||||||
// Was the asset updated?
|
// Was the asset updated?
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
|
||||||
|
|
||||||
if ((isset($user)) && ($backto == 'user')) {
|
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
return redirect()->route('users.show', $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
|
return Helper::getRedirectOption($asset, $assetId, 'Assets');
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkin.success'));
|
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
||||||
|
|
|
@ -9,7 +9,9 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetCheckoutRequest;
|
use App\Http\Requests\AssetCheckoutRequest;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class AssetCheckoutController extends Controller
|
class AssetCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -22,9 +24,9 @@ class AssetCheckoutController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function create($assetId)
|
public function create($assetId) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (is_null($asset = Asset::with('company')->find(e($assetId)))) {
|
if (is_null($asset = Asset::with('company')->find(e($assetId)))) {
|
||||||
|
@ -33,11 +35,17 @@ class AssetCheckoutController extends Controller
|
||||||
|
|
||||||
$this->authorize('checkout', $asset);
|
$this->authorize('checkout', $asset);
|
||||||
|
|
||||||
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($asset->availableForCheckout()) {
|
if ($asset->availableForCheckout()) {
|
||||||
return view('hardware/checkout', compact('asset'))
|
return view('hardware/checkout', compact('asset'))
|
||||||
->with('statusLabel_list', Helper::deployableStatusLabelList());
|
->with('statusLabel_list', Helper::deployableStatusLabelList())
|
||||||
|
->with('table_name', 'Assets');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +54,9 @@ class AssetCheckoutController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param AssetCheckoutRequest $request
|
* @param AssetCheckoutRequest $request
|
||||||
* @param int $assetId
|
|
||||||
* @return Redirect
|
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function store(AssetCheckoutRequest $request, $assetId)
|
public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
|
@ -60,9 +66,14 @@ class AssetCheckoutController extends Controller
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
|
||||||
}
|
}
|
||||||
$this->authorize('checkout', $asset);
|
$this->authorize('checkout', $asset);
|
||||||
$admin = Auth::user();
|
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget($asset);
|
if (!$asset->model) {
|
||||||
|
return redirect()->route('hardware.show', $asset->id)->with('error', trans('admin/hardware/general.model_invalid_fix'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$admin = auth()->user();
|
||||||
|
|
||||||
|
$target = $this->determineCheckoutTarget();
|
||||||
|
|
||||||
$asset = $this->updateAssetLocation($asset, $target);
|
$asset = $this->updateAssetLocation($asset, $target);
|
||||||
|
|
||||||
|
@ -97,11 +108,12 @@ class AssetCheckoutController extends Controller
|
||||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Session::put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
|
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
||||||
|
return Helper::getRedirectOption($request, $assetId, 'Assets');
|
||||||
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
|
|
|
@ -7,8 +7,12 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\UploadFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Support\Facades\Response;
|
use \Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
class AssetFilesController extends Controller
|
class AssetFilesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -17,12 +21,12 @@ class AssetFilesController extends Controller
|
||||||
*
|
*
|
||||||
* @param UploadFileRequest $request
|
* @param UploadFileRequest $request
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*@since [v1.0]
|
*@since [v1.0]
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(UploadFileRequest $request, $assetId = null)
|
public function store(UploadFileRequest $request, $assetId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
@ -38,7 +42,7 @@ class AssetFilesController extends Controller
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||||
|
|
||||||
$asset->logUpload($file_name, e($request->get('notes')));
|
$asset->logUpload($file_name, $request->get('notes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
||||||
|
@ -54,10 +58,8 @@ class AssetFilesController extends Controller
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show($assetId = null, $fileId = null)
|
public function show($assetId = null, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
|
||||||
{
|
{
|
||||||
$asset = Asset::find($assetId);
|
$asset = Asset::find($assetId);
|
||||||
// the asset is valid
|
// the asset is valid
|
||||||
|
@ -70,7 +72,6 @@ class AssetFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = 'private_uploads/assets/'.$log->filename;
|
$file = 'private_uploads/assets/'.$log->filename;
|
||||||
\Log::debug('Checking for '.$file);
|
|
||||||
|
|
||||||
if ($log->action_type == 'audit') {
|
if ($log->action_type == 'audit') {
|
||||||
$file = 'private_uploads/audits/'.$log->filename;
|
$file = 'private_uploads/audits/'.$log->filename;
|
||||||
|
@ -106,10 +107,8 @@ class AssetFilesController extends Controller
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @param int $fileId
|
* @param int $fileId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($assetId = null, $fileId = null)
|
public function destroy($assetId = null, $fileId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
$asset = Asset::find($assetId);
|
$asset = Asset::find($assetId);
|
||||||
$this->authorize('update', $asset);
|
$this->authorize('update', $asset);
|
||||||
|
@ -132,7 +131,6 @@ class AssetFilesController extends Controller
|
||||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the hardware management page
|
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Manufacturer;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
|
@ -20,14 +20,16 @@ use Illuminate\Support\Facades\Auth;
|
||||||
use App\View\Label;
|
use App\View\Label;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\View;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use League\Csv\Reader;
|
use League\Csv\Reader;
|
||||||
use Illuminate\Support\Facades\Redirect;
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to assets for
|
* This class controls all actions related to assets for
|
||||||
|
@ -55,10 +57,8 @@ class AssetsController extends Controller
|
||||||
* @see AssetController::getDatatable() method that generates the JSON response
|
* @see AssetController::getDatatable() method that generates the JSON response
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request) : View
|
||||||
{
|
{
|
||||||
$this->authorize('index', Asset::class);
|
$this->authorize('index', Asset::class);
|
||||||
$company = Company::find($request->input('company_id'));
|
$company = Company::find($request->input('company_id'));
|
||||||
|
@ -72,13 +72,12 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return View
|
|
||||||
* @internal param int $model_id
|
* @internal param int $model_id
|
||||||
*/
|
*/
|
||||||
public function create(Request $request)
|
public function create(Request $request) : View
|
||||||
{
|
{
|
||||||
$this->authorize('create', Asset::class);
|
$this->authorize('create', Asset::class);
|
||||||
$view = View::make('hardware/edit')
|
$view = view('hardware/edit')
|
||||||
->with('statuslabel_list', Helper::statusLabelList())
|
->with('statuslabel_list', Helper::statusLabelList())
|
||||||
->with('item', new Asset)
|
->with('item', new Asset)
|
||||||
->with('statuslabel_types', Helper::statusTypeList());
|
->with('statuslabel_types', Helper::statusTypeList());
|
||||||
|
@ -96,9 +95,8 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize(Asset::class);
|
$this->authorize(Asset::class);
|
||||||
|
|
||||||
|
@ -198,7 +196,7 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($target)) {
|
if (isset($target)) {
|
||||||
$asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = true;
|
$success = true;
|
||||||
|
@ -207,7 +205,6 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
\Log::debug(e($asset->asset_tag));
|
|
||||||
return redirect()->route('hardware.index')
|
return redirect()->route('hardware.index')
|
||||||
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
||||||
|
|
||||||
|
@ -217,11 +214,6 @@ class AssetsController extends Controller
|
||||||
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOptionCookie(Request $request){
|
|
||||||
$value = $request->cookie('optional_info');
|
|
||||||
echo $value;
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view that presents a form to edit an existing asset.
|
* Returns a view that presents a form to edit an existing asset.
|
||||||
|
@ -229,9 +221,9 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function edit($assetId = null)
|
public function edit($assetId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
if (! $item = Asset::find($assetId)) {
|
if (! $item = Asset::find($assetId)) {
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
|
@ -252,9 +244,9 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function show($assetId = null)
|
public function show($assetId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$asset = Asset::withTrashed()->find($assetId);
|
$asset = Asset::withTrashed()->find($assetId);
|
||||||
$this->authorize('view', $asset);
|
$this->authorize('view', $asset);
|
||||||
|
@ -292,11 +284,10 @@ class AssetsController extends Controller
|
||||||
* Validate and process asset edit form.
|
* Validate and process asset edit form.
|
||||||
*
|
*
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return \Illuminate\Http\RedirectResponse|Redirect
|
* @since [v1.0]
|
||||||
*@since [v1.0]
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $assetId = null)
|
public function update(ImageUploadRequest $request, $assetId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
|
@ -308,7 +299,8 @@ class AssetsController extends Controller
|
||||||
$asset->status_id = $request->input('status_id', null);
|
$asset->status_id = $request->input('status_id', null);
|
||||||
$asset->warranty_months = $request->input('warranty_months', null);
|
$asset->warranty_months = $request->input('warranty_months', null);
|
||||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||||
$asset->purchase_date = $request->input('purchase_date', null);
|
$asset->purchase_date = $request->input('purchase_date', null);
|
||||||
|
$asset->next_audit_date = $request->input('next_audit_date', null);
|
||||||
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
|
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
|
||||||
$asset->purchase_date = $request->input('purchase_date', null);
|
$asset->purchase_date = $request->input('purchase_date', null);
|
||||||
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||||
|
@ -410,9 +402,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function destroy($assetId)
|
public function destroy($assetId) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (is_null($asset = Asset::find($assetId))) {
|
if (is_null($asset = Asset::find($assetId))) {
|
||||||
|
@ -444,9 +435,8 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function getAssetBySerial(Request $request)
|
public function getAssetBySerial(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$topsearch = ($request->get('topsearch')=="true");
|
$topsearch = ($request->get('topsearch')=="true");
|
||||||
|
|
||||||
|
@ -462,9 +452,9 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getAssetByTag(Request $request, $tag=null)
|
public function getAssetByTag(Request $request, $tag=null) : RedirectResponse
|
||||||
{
|
{
|
||||||
$tag = $tag ? $tag : $request->get('assetTag');
|
$tag = $tag ? $tag : $request->get('assetTag');
|
||||||
$topsearch = ($request->get('topsearch') == 'true');
|
$topsearch = ($request->get('topsearch') == 'true');
|
||||||
|
@ -484,9 +474,8 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Response
|
|
||||||
*/
|
*/
|
||||||
public function getQrCode($assetId = null)
|
public function getQrCode($assetId = null) : Response | BinaryFileResponse | string | bool
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
|
||||||
|
@ -513,6 +502,7 @@ class AssetsController extends Controller
|
||||||
|
|
||||||
return 'That asset is invalid';
|
return 'That asset is invalid';
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -560,7 +550,7 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [L. Swartzendruber] [<logan.swartzendruber@gmail.com>
|
* @author [L. Swartzendruber] [<logan.swartzendruber@gmail.com>
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getLabel($assetId = null)
|
public function getLabel($assetId = null)
|
||||||
{
|
{
|
||||||
|
@ -584,7 +574,7 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getClone($assetId = null)
|
public function getClone($assetId = null)
|
||||||
{
|
{
|
||||||
|
@ -613,7 +603,7 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getImportHistory()
|
public function getImportHistory()
|
||||||
{
|
{
|
||||||
|
@ -635,7 +625,7 @@ class AssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.3]
|
* @since [v3.3]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function postImportHistory(Request $request)
|
public function postImportHistory(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -729,8 +719,8 @@ class AssetsController extends Controller
|
||||||
Actionlog::firstOrCreate([
|
Actionlog::firstOrCreate([
|
||||||
'item_id' => $asset->id,
|
'item_id' => $asset->id,
|
||||||
'item_type' => Asset::class,
|
'item_type' => Asset::class,
|
||||||
'user_id' => Auth::user()->id,
|
'user_id' => auth()->id(),
|
||||||
'note' => 'Checkout imported by '.Auth::user()->present()->fullName().' from history importer',
|
'note' => 'Checkout imported by '.auth()->user()->present()->fullName().' from history importer',
|
||||||
'target_id' => $item[$asset_tag][$batch_counter]['user_id'],
|
'target_id' => $item[$asset_tag][$batch_counter]['user_id'],
|
||||||
'target_type' => User::class,
|
'target_type' => User::class,
|
||||||
'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'],
|
'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'],
|
||||||
|
@ -757,8 +747,8 @@ class AssetsController extends Controller
|
||||||
Actionlog::firstOrCreate([
|
Actionlog::firstOrCreate([
|
||||||
'item_id' => $item[$asset_tag][$batch_counter]['asset_id'],
|
'item_id' => $item[$asset_tag][$batch_counter]['asset_id'],
|
||||||
'item_type' => Asset::class,
|
'item_type' => Asset::class,
|
||||||
'user_id' => Auth::user()->id,
|
'user_id' => auth()->id(),
|
||||||
'note' => 'Checkin imported by '.Auth::user()->present()->fullName().' from history importer',
|
'note' => 'Checkin imported by '.auth()->user()->present()->fullName().' from history importer',
|
||||||
'target_id' => null,
|
'target_id' => null,
|
||||||
'created_at' => $checkin_date,
|
'created_at' => $checkin_date,
|
||||||
'action_type' => 'checkin',
|
'action_type' => 'checkin',
|
||||||
|
@ -795,7 +785,7 @@ class AssetsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getRestore($assetId = null)
|
public function getRestore($assetId = null)
|
||||||
{
|
{
|
||||||
|
@ -854,15 +844,15 @@ class AssetsController extends Controller
|
||||||
return view('hardware/audit-due');
|
return view('hardware/audit-due');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function overdueForAudit()
|
public function dueForCheckin()
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('checkin', Asset::class);
|
||||||
|
|
||||||
return view('hardware/audit-overdue');
|
return view('hardware/checkin-due');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function auditStore(Request $request, $id)
|
public function auditStore(UploadFileRequest $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('audit', Asset::class);
|
$this->authorize('audit', Asset::class);
|
||||||
|
|
||||||
|
@ -879,7 +869,21 @@ class AssetsController extends Controller
|
||||||
|
|
||||||
$asset = Asset::findOrFail($id);
|
$asset = Asset::findOrFail($id);
|
||||||
|
|
||||||
// We don't want to log this as a normal update, so let's bypass that
|
/**
|
||||||
|
* Even though we do a save() further down, we don't want to log this as a "normal" asset update,
|
||||||
|
* which would trigger the Asset Observer and would log an asset *update* log entry (because the
|
||||||
|
* de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
|
||||||
|
* the audit log entry we're creating through this controller.
|
||||||
|
*
|
||||||
|
* To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
|
||||||
|
* that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
|
||||||
|
* will bypass normal model-level validation that's usually handled at the observer )
|
||||||
|
*
|
||||||
|
* We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
|
||||||
|
* which manually invokes Watson Validating to make sure the asset's model is valid.
|
||||||
|
*
|
||||||
|
* @see \App\Observers\AssetObserver::updating()
|
||||||
|
*/
|
||||||
$asset->unsetEventDispatcher();
|
$asset->unsetEventDispatcher();
|
||||||
|
|
||||||
$asset->next_audit_date = $request->input('next_audit_date');
|
$asset->next_audit_date = $request->input('next_audit_date');
|
||||||
|
@ -888,29 +892,27 @@ class AssetsController extends Controller
|
||||||
// Check to see if they checked the box to update the physical location,
|
// Check to see if they checked the box to update the physical location,
|
||||||
// not just note it in the audit notes
|
// not just note it in the audit notes
|
||||||
if ($request->input('update_location') == '1') {
|
if ($request->input('update_location') == '1') {
|
||||||
Log::debug('update location in audit');
|
|
||||||
$asset->location_id = $request->input('location_id');
|
$asset->location_id = $request->input('location_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
|
||||||
|
* We have to invoke this manually because of the unsetEventDispatcher() above.)
|
||||||
|
*/
|
||||||
|
if ($asset->isValid() && $asset->save()) {
|
||||||
|
|
||||||
if ($asset->save()) {
|
$file_name = null;
|
||||||
$file_name = '';
|
// Create the image (if one was chosen.)
|
||||||
// Upload an image, if attached
|
|
||||||
if ($request->hasFile('image')) {
|
if ($request->hasFile('image')) {
|
||||||
$path = 'private_uploads/audits';
|
$file_name = $request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image'));
|
||||||
if (! Storage::exists($path)) {
|
|
||||||
Storage::makeDirectory($path, 775);
|
|
||||||
}
|
|
||||||
$upload = $image = $request->file('image');
|
|
||||||
$ext = $image->getClientOriginalExtension();
|
|
||||||
$file_name = 'audit-'.str_random(18).'.'.$ext;
|
|
||||||
Storage::putFileAs($path, $upload, $file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
|
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
|
||||||
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
|
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestedIndex($user_id = null)
|
public function getRequestedIndex($user_id = null)
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Assets;
|
namespace App\Http\Controllers\Assets;
|
||||||
|
|
||||||
use App\Models\Actionlog;
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\CheckInOutRequest;
|
use App\Http\Controllers\CheckInOutRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
@ -12,12 +11,15 @@ use App\Models\Statuslabel;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\View\Label;
|
use App\View\Label;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use App\Http\Requests\AssetCheckoutRequest;
|
use App\Http\Requests\AssetCheckoutRequest;
|
||||||
use App\Models\CustomField;
|
use App\Models\CustomField;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
|
||||||
class BulkAssetsController extends Controller
|
class BulkAssetsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -34,12 +36,10 @@ class BulkAssetsController extends Controller
|
||||||
* action would make a lot more sense here and make things a lot more clear.
|
* action would make a lot more sense here and make things a lot more clear.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return View
|
|
||||||
* @internal param int $assetId
|
* @internal param int $assetId
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request)
|
public function edit(Request $request) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
|
@ -189,11 +189,10 @@ class BulkAssetsController extends Controller
|
||||||
* Save bulk edits
|
* Save bulk edits
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return Redirect
|
|
||||||
* @internal param array $assets
|
* @internal param array $assets
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
*/
|
*/
|
||||||
public function update(Request $request)
|
public function update(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
$has_errors = 0;
|
$has_errors = 0;
|
||||||
|
@ -214,7 +213,7 @@ class BulkAssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$assets = Asset::whereIn('id', array_keys($request->input('ids')))->get();
|
$assets = Asset::whereIn('id', $request->input('ids'))->get();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -379,28 +378,30 @@ class BulkAssetsController extends Controller
|
||||||
foreach ($asset->model->fieldset->fields as $field) {
|
foreach ($asset->model->fieldset->fields as $field) {
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
if (Gate::allows('admin')) {
|
||||||
|
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the decrypted existing value is different from one we just submitted
|
|
||||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
|
||||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
|
||||||
* different times will have different values, so it will *look* like it was updated
|
|
||||||
* but it wasn't.
|
|
||||||
*/
|
|
||||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
|
||||||
$asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]);
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
* Check if the decrypted existing value is different from one we just submitted
|
||||||
|
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||||
|
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||||
|
* different times will have different values, so it will *look* like it was updated
|
||||||
|
* but it wasn't.
|
||||||
*/
|
*/
|
||||||
unset($this->update_array[$field->db_column]);
|
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||||
unset($asset->{$field->db_column});
|
$asset->{$field->db_column} = Crypt::encrypt($this->update_array[$field->db_column]);
|
||||||
}
|
} else {
|
||||||
|
/*
|
||||||
|
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||||
|
*/
|
||||||
|
unset($this->update_array[$field->db_column]);
|
||||||
|
unset($asset->{$field->db_column});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These custom fields aren't encrypted, just carry on as usual
|
* These custom fields aren't encrypted, just carry on as usual
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
||||||
|
@ -452,9 +453,8 @@ class BulkAssetsController extends Controller
|
||||||
/**
|
/**
|
||||||
* Adds parameter to update array for an item if it exists in request
|
* Adds parameter to update array for an item if it exists in request
|
||||||
* @param string $field field name
|
* @param string $field field name
|
||||||
* @return BulkAssetsController Model for Chaining
|
|
||||||
*/
|
*/
|
||||||
protected function conditionallyAddItem($field)
|
protected function conditionallyAddItem($field) : BulkAssetsController
|
||||||
{
|
{
|
||||||
if (request()->filled($field)) {
|
if (request()->filled($field)) {
|
||||||
$this->update_array[$field] = request()->input($field);
|
$this->update_array[$field] = request()->input($field);
|
||||||
|
@ -468,12 +468,10 @@ class BulkAssetsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @internal param array $assets
|
* @internal param array $assets
|
||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
*/
|
*/
|
||||||
public function destroy(Request $request)
|
public function destroy(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Asset::class);
|
$this->authorize('delete', Asset::class);
|
||||||
|
|
||||||
|
@ -502,27 +500,23 @@ class BulkAssetsController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show Bulk Checkout Page
|
* Show Bulk Checkout Page
|
||||||
* @return View View to checkout multiple assets
|
|
||||||
*/
|
*/
|
||||||
public function showCheckout()
|
public function showCheckout() : View
|
||||||
{
|
{
|
||||||
$this->authorize('checkout', Asset::class);
|
$this->authorize('checkout', Asset::class);
|
||||||
// Filter out assets that are not deployable.
|
|
||||||
|
|
||||||
return view('hardware/bulk-checkout');
|
return view('hardware/bulk-checkout');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process Multiple Checkout Request
|
* Process Multiple Checkout Request
|
||||||
* @return View
|
|
||||||
*/
|
*/
|
||||||
public function storeCheckout(AssetCheckoutRequest $request)
|
public function storeCheckout(AssetCheckoutRequest $request) : RedirectResponse | ModelNotFoundException
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->authorize('checkout', Asset::class);
|
$this->authorize('checkout', Asset::class);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$admin = Auth::user();
|
$admin = auth()->user();
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget();
|
$target = $this->determineCheckoutTarget();
|
||||||
|
|
||||||
|
@ -581,17 +575,19 @@ class BulkAssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public function restore(Request $request) {
|
public function restore(Request $request) : RedirectResponse
|
||||||
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
$assetIds = $request->get('ids');
|
$assetIds = $request->get('ids');
|
||||||
if (empty($assetIds)) {
|
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
|
if (empty($assetIds)) {
|
||||||
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
|
||||||
} else {
|
} else {
|
||||||
foreach ($assetIds as $key => $assetId) {
|
foreach ($assetIds as $key => $assetId) {
|
||||||
$asset = Asset::withTrashed()->find($assetId);
|
$asset = Asset::withTrashed()->find($assetId);
|
||||||
$asset->restore();
|
$asset->restore();
|
||||||
}
|
}
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
class ForgotPasswordController extends Controller
|
class ForgotPasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -79,16 +79,16 @@ class ForgotPasswordController extends Controller
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
\Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
|
Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent timing attack to enumerate users.
|
// Prevent timing attack to enumerate users.
|
||||||
usleep(500000 + random_int(0, 1500000));
|
usleep(500000 + random_int(0, 1500000));
|
||||||
|
|
||||||
if ($response === \Password::RESET_LINK_SENT) {
|
if ($response === \Password::RESET_LINK_SENT) {
|
||||||
\Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');
|
Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent');
|
||||||
} else {
|
} else {
|
||||||
\Log::info('Password reset attempt: User matching username '.$request->input('username').' NOT FOUND or user is inactive');
|
Log::info('Password reset attempt: User matching username '.$request->input('username').' NOT FOUND or user is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,7 +16,7 @@ use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,12 +122,12 @@ class LoginController extends Controller
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
} else {
|
} else {
|
||||||
$username = $saml->getUsername();
|
$username = $saml->getUsername();
|
||||||
\Log::debug("SAML user '$username' could not be found in database.");
|
Log::debug("SAML user '$username' could not be found in database.");
|
||||||
$request->session()->flash('error', trans('auth/message.signin.error'));
|
$request->session()->flash('error', trans('auth/message.signin.error'));
|
||||||
$saml->clearData();
|
$saml->clearData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user = Auth::user()) {
|
if ($user = auth()->user()) {
|
||||||
$user->last_login = \Carbon::now();
|
$user->last_login = \Carbon::now();
|
||||||
$user->saveQuietly();
|
$user->saveQuietly();
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ class LoginController extends Controller
|
||||||
$s->save();
|
$s->save();
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
|
Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ class LoginController extends Controller
|
||||||
|
|
||||||
// Better logging
|
// Better logging
|
||||||
if (empty($samlData)) {
|
if (empty($samlData)) {
|
||||||
\Log::debug("SAML page requested, but samlData seems empty.");
|
Log::debug("SAML page requested, but samlData seems empty.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,19 +261,19 @@ class LoginController extends Controller
|
||||||
/**
|
/**
|
||||||
* Account sign in form processing.
|
* Account sign in form processing.
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
//If the environment is set to ALWAYS require SAML, return access denied
|
//If the environment is set to ALWAYS require SAML, return access denied
|
||||||
if (config('app.require_saml')) {
|
if (config('app.require_saml')) {
|
||||||
\Log::debug('require SAML is enabled in the .env - return a 403');
|
Log::debug('require SAML is enabled in the .env - return a 403');
|
||||||
return view('errors.403');
|
return view('errors.403');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->login_common_disabled == '1') {
|
if (Setting::getSettings()->login_common_disabled == '1') {
|
||||||
\Log::debug('login_common_disabled is set to 1 - return a 403');
|
Log::debug('login_common_disabled is set to 1 - return a 403');
|
||||||
return view('errors.403');
|
return view('errors.403');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ class LoginController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user = Auth::user()) {
|
if ($user = auth()->user()) {
|
||||||
$user->last_login = \Carbon::now();
|
$user->last_login = \Carbon::now();
|
||||||
$user->activated = 1;
|
$user->activated = 1;
|
||||||
$user->saveQuietly();
|
$user->saveQuietly();
|
||||||
|
@ -339,7 +339,7 @@ class LoginController extends Controller
|
||||||
/**
|
/**
|
||||||
* Two factor enrollment page
|
* Two factor enrollment page
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getTwoFactorEnroll()
|
public function getTwoFactorEnroll()
|
||||||
{
|
{
|
||||||
|
@ -350,7 +350,7 @@ class LoginController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$user = Auth::user();
|
$user = auth()->user();
|
||||||
|
|
||||||
// We wouldn't normally see this page if 2FA isn't enforced via the
|
// 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,
|
// \App\Http\Middleware\CheckForTwoFactor middleware AND if a device isn't enrolled,
|
||||||
|
@ -389,7 +389,7 @@ class LoginController extends Controller
|
||||||
/**
|
/**
|
||||||
* Two factor code form page
|
* Two factor code form page
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function getTwoFactorAuth()
|
public function getTwoFactorAuth()
|
||||||
{
|
{
|
||||||
|
@ -398,7 +398,7 @@ class LoginController extends Controller
|
||||||
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
|
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = auth()->user();
|
||||||
|
|
||||||
// Check whether there is a device enrolled.
|
// Check whether there is a device enrolled.
|
||||||
// This *should* be handled via the \App\Http\Middleware\CheckForTwoFactor middleware
|
// This *should* be handled via the \App\Http\Middleware\CheckForTwoFactor middleware
|
||||||
|
@ -415,7 +415,7 @@ class LoginController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function postTwoFactorAuth(Request $request)
|
public function postTwoFactorAuth(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -427,11 +427,7 @@ class LoginController extends Controller
|
||||||
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
|
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $request->has('two_factor_secret')) { // TODO this seems almost the same as above?
|
$user = auth()->user();
|
||||||
return redirect()->route('two-factor')->with('error', 'Two-factor code is required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = Auth::user();
|
|
||||||
$secret = $request->input('two_factor_secret');
|
$secret = $request->input('two_factor_secret');
|
||||||
|
|
||||||
if (Google2FA::verifyKey($user->two_factor_secret, $secret)) {
|
if (Google2FA::verifyKey($user->two_factor_secret, $secret)) {
|
||||||
|
@ -439,7 +435,7 @@ class LoginController extends Controller
|
||||||
$user->saveQuietly();
|
$user->saveQuietly();
|
||||||
$request->session()->put('2fa_authed', $user->id);
|
$request->session()->put('2fa_authed', $user->id);
|
||||||
|
|
||||||
return redirect()->route('home')->with('success', 'You are logged in!');
|
return redirect()->route('home')->with('success', trans('auth/message.signin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
|
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
|
||||||
|
@ -451,7 +447,7 @@ class LoginController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function logout(Request $request)
|
public function logout(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -537,7 +533,7 @@ class LoginController extends Controller
|
||||||
|
|
||||||
$minutes = round($seconds / 60);
|
$minutes = round($seconds / 60);
|
||||||
|
|
||||||
$message = \Lang::get('auth/message.throttle', ['minutes' => $minutes]);
|
$message = trans('auth/message.throttle', ['minutes' => $minutes]);
|
||||||
|
|
||||||
return redirect()->back()
|
return redirect()->back()
|
||||||
->withInput($request->only($this->username(), 'remember'))
|
->withInput($request->only($this->username(), 'remember'))
|
||||||
|
|
|
@ -7,7 +7,7 @@ use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ class ResetPasswordController extends Controller
|
||||||
$credentials = $request->only('email', 'token');
|
$credentials = $request->only('email', 'token');
|
||||||
|
|
||||||
if (is_null($this->broker()->getUser($credentials))) {
|
if (is_null($this->broker()->getUser($credentials))) {
|
||||||
\Log::debug('Password reset form FAILED - this token is not valid.');
|
Log::debug('Password reset form FAILED - this token is not valid.');
|
||||||
return redirect()->route('password.request')->with('error', trans('passwords.token'));
|
return redirect()->route('password.request')->with('error', trans('passwords.token'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +89,10 @@ class ResetPasswordController extends Controller
|
||||||
|
|
||||||
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
||||||
|
|
||||||
\Log::debug('Checking if '.$request->input('username').' exists');
|
Log::debug('Checking if '.$request->input('username').' exists');
|
||||||
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
|
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
|
||||||
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
|
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
|
||||||
\Log::debug($user->username.' exists');
|
Log::debug($user->username.' exists');
|
||||||
|
|
||||||
|
|
||||||
// handle the password validation rules set by the admin settings
|
// handle the password validation rules set by the admin settings
|
||||||
|
@ -112,17 +112,17 @@ class ResetPasswordController extends Controller
|
||||||
|
|
||||||
// Check if the password reset above actually worked
|
// Check if the password reset above actually worked
|
||||||
if ($response == \Password::PASSWORD_RESET) {
|
if ($response == \Password::PASSWORD_RESET) {
|
||||||
\Log::debug('Password reset for '.$user->username.' worked');
|
Log::debug('Password reset for '.$user->username.' worked');
|
||||||
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
|
Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
|
||||||
return redirect()->back()->withInput($request->only('email'))->with('success', trans('passwords.reset'));
|
return redirect()->back()->withInput($request->only('email'))->with('success', trans('passwords.reset'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
\Log::debug('Password reset for '.$request->input('username').' FAILED - user does not exist or does not have an email address - but make it look like it succeeded');
|
Log::debug('Password reset for '.$request->input('username').' FAILED - user does not exist or does not have an email address - but make it look like it succeeded');
|
||||||
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
return redirect()->guest('login')->with('success', trans('passwords.reset'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Services\Saml;
|
use App\Services\Saml;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller provides the endpoint for SAML communication and metadata.
|
* This controller provides the endpoint for SAML communication and metadata.
|
||||||
|
@ -51,7 +51,7 @@ class SamlController extends Controller
|
||||||
$metadata = $this->saml->getSPMetadata();
|
$metadata = $this->saml->getSPMetadata();
|
||||||
|
|
||||||
if (empty($metadata)) {
|
if (empty($metadata)) {
|
||||||
\Log::debug('SAML metadata is empty - return a 403');
|
Log::debug('SAML metadata is empty - return a 403');
|
||||||
return response()->view('errors.403', [], 403);
|
return response()->view('errors.403', [], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class SamlController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,7 @@ class SamlController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function acs(Request $request)
|
public function acs(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ class SamlController extends Controller
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return Redirect
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function sls(Request $request)
|
public function sls(Request $request)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,8 +5,8 @@ namespace App\Http\Controllers;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Facades\Redirect;
|
use \Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
class BulkAssetModelsController extends Controller
|
class BulkAssetModelsController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,8 @@ class BulkAssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.7]
|
* @since [v1.7]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request)
|
public function edit(Request $request) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$models_raw_array = $request->input('ids');
|
$models_raw_array = $request->input('ids');
|
||||||
|
|
||||||
|
@ -61,9 +60,8 @@ class BulkAssetModelsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.7]
|
* @since [v1.7]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request)
|
public function update(Request $request): View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', AssetModel::class);
|
$this->authorize('update', AssetModel::class);
|
||||||
|
|
||||||
|
@ -105,9 +103,8 @@ class BulkAssetModelsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return Redirect
|
|
||||||
*/
|
*/
|
||||||
public function destroy(Request $request)
|
public function destroy(Request $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', AssetModel::class);
|
$this->authorize('delete', AssetModel::class);
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,11 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Category as Category;
|
use App\Models\Category;
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Str;
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to Categories for
|
* This class controls all actions related to Categories for
|
||||||
|
@ -25,10 +26,8 @@ class CategoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @see CategoriesController::getDatatable() method that generates the JSON response
|
* @see CategoriesController::getDatatable() method that generates the JSON response
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
// Show the page
|
// Show the page
|
||||||
$this->authorize('view', Category::class);
|
$this->authorize('view', Category::class);
|
||||||
|
@ -42,10 +41,8 @@ class CategoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @see CategoriesController::store() method that stores the data
|
* @see CategoriesController::store() method that stores the data
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create() : View
|
||||||
{
|
{
|
||||||
// Show the page
|
// Show the page
|
||||||
$this->authorize('create', Category::class);
|
$this->authorize('create', Category::class);
|
||||||
|
@ -61,10 +58,8 @@ class CategoriesController extends Controller
|
||||||
* @see CategoriesController::create() method that makes the form.
|
* @see CategoriesController::create() method that makes the form.
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Category::class);
|
$this->authorize('create', Category::class);
|
||||||
$category = new Category();
|
$category = new Category();
|
||||||
|
@ -91,10 +86,8 @@ class CategoriesController extends Controller
|
||||||
* @see CategoriesController::postEdit() method saves the data
|
* @see CategoriesController::postEdit() method saves the data
|
||||||
* @param int $categoryId
|
* @param int $categoryId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit($categoryId = null)
|
public function edit($categoryId = null) : RedirectResponse | View
|
||||||
{
|
{
|
||||||
$this->authorize('update', Category::class);
|
$this->authorize('update', Category::class);
|
||||||
if (is_null($item = Category::find($categoryId))) {
|
if (is_null($item = Category::find($categoryId))) {
|
||||||
|
@ -112,23 +105,31 @@ class CategoriesController extends Controller
|
||||||
* @see CategoriesController::getEdit() method that makes the form.
|
* @see CategoriesController::getEdit() method that makes the form.
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $categoryId
|
* @param int $categoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $categoryId = null)
|
public function update(ImageUploadRequest $request, $categoryId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Category::class);
|
$this->authorize('update', Category::class);
|
||||||
if (is_null($category = Category::find($categoryId))) {
|
if (is_null($category = Category::find($categoryId))) {
|
||||||
// Redirect to the categories management page
|
// Redirect to the categories management page
|
||||||
return redirect()->to('admin/categories')->with('error', trans('admin/categories/message.does_not_exist'));
|
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the category data
|
// Update the category data
|
||||||
$category->name = $request->input('name');
|
$category->name = $request->input('name');
|
||||||
// If the item count is > 0, we disable the category type in the edit. Disabled items
|
// If the item count is > 0, we disable the category type in the edit. Disabled items
|
||||||
// don't POST, so if the category_type is blank we just set it to the default.
|
// don't POST, so if the category_type is blank we just set it to the default.
|
||||||
|
|
||||||
|
|
||||||
|
// Don't allow the user to change the category_type once it's been created
|
||||||
|
if (($request->filled('category_type') && ($category->itemCount() > 0))) {
|
||||||
|
$request->validate(['category_type' => 'in:'.$category->category_type]);
|
||||||
|
}
|
||||||
|
|
||||||
$category->category_type = $request->input('category_type', $category->category_type);
|
$category->category_type = $request->input('category_type', $category->category_type);
|
||||||
|
|
||||||
|
$category->fill($request->all());
|
||||||
|
|
||||||
$category->eula_text = $request->input('eula_text');
|
$category->eula_text = $request->input('eula_text');
|
||||||
$category->use_default_eula = $request->input('use_default_eula', '0');
|
$category->use_default_eula = $request->input('use_default_eula', '0');
|
||||||
$category->require_acceptance = $request->input('require_acceptance', '0');
|
$category->require_acceptance = $request->input('require_acceptance', '0');
|
||||||
|
@ -150,10 +151,8 @@ class CategoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $categoryId
|
* @param int $categoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($categoryId)
|
public function destroy($categoryId) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Category::class);
|
$this->authorize('delete', Category::class);
|
||||||
// Check if the category exists
|
// Check if the category exists
|
||||||
|
@ -178,11 +177,9 @@ class CategoriesController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @see CategoriesController::getDataView() method that generates the JSON response
|
* @see CategoriesController::getDataView() method that generates the JSON response
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Category::class);
|
$this->authorize('view', Category::class);
|
||||||
if ($category = Category::find($id)) {
|
if ($category = Category::find($id)) {
|
||||||
|
|
|
@ -11,9 +11,8 @@ trait CheckInOutRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Find target for checkout
|
* Find target for checkout
|
||||||
* @return SnipeModel Target asset is being checked out to.
|
|
||||||
*/
|
*/
|
||||||
protected function determineCheckoutTarget()
|
protected function determineCheckoutTarget() : ?SnipeModel
|
||||||
{
|
{
|
||||||
// This item is checked out to a location
|
// This item is checked out to a location
|
||||||
switch (request('checkout_to_type')) {
|
switch (request('checkout_to_type')) {
|
||||||
|
@ -34,7 +33,7 @@ trait CheckInOutRequest
|
||||||
* @param SnipeModel $target Target with location
|
* @param SnipeModel $target Target with location
|
||||||
* @return Asset Asset being updated
|
* @return Asset Asset being updated
|
||||||
*/
|
*/
|
||||||
protected function updateAssetLocation($asset, $target)
|
protected function updateAssetLocation($asset, $target) : Asset
|
||||||
{
|
{
|
||||||
switch (request('checkout_to_type')) {
|
switch (request('checkout_to_type')) {
|
||||||
case 'location':
|
case 'location':
|
||||||
|
|
|
@ -6,6 +6,9 @@ use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Companies for
|
* This controller handles all actions related to Companies for
|
||||||
|
@ -20,10 +23,8 @@ final class CompaniesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$this->authorize('view', Company::class);
|
$this->authorize('view', Company::class);
|
||||||
|
|
||||||
|
@ -35,10 +36,8 @@ final class CompaniesController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create() : View
|
||||||
{
|
{
|
||||||
$this->authorize('create', Company::class);
|
$this->authorize('create', Company::class);
|
||||||
|
|
||||||
|
@ -51,10 +50,8 @@ final class CompaniesController extends Controller
|
||||||
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', Company::class);
|
$this->authorize('create', Company::class);
|
||||||
|
|
||||||
|
@ -80,10 +77,8 @@ final class CompaniesController extends Controller
|
||||||
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @param int $companyId
|
* @param int $companyId
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit($companyId)
|
public function edit($companyId) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($item = Company::find($companyId))) {
|
if (is_null($item = Company::find($companyId))) {
|
||||||
return redirect()->route('companies.index')
|
return redirect()->route('companies.index')
|
||||||
|
@ -102,10 +97,8 @@ final class CompaniesController extends Controller
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @param ImageUploadRequest $request
|
* @param ImageUploadRequest $request
|
||||||
* @param int $companyId
|
* @param int $companyId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $companyId)
|
public function update(ImageUploadRequest $request, $companyId) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($company = Company::find($companyId))) {
|
if (is_null($company = Company::find($companyId))) {
|
||||||
return redirect()->route('companies.index')->with('error', trans('admin/companies/message.does_not_exist'));
|
return redirect()->route('companies.index')->with('error', trans('admin/companies/message.does_not_exist'));
|
||||||
|
@ -134,10 +127,8 @@ final class CompaniesController extends Controller
|
||||||
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @param int $companyId
|
* @param int $companyId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($companyId)
|
public function destroy($companyId) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($company = Company::find($companyId))) {
|
if (is_null($company = Company::find($companyId))) {
|
||||||
return redirect()->route('companies.index')
|
return redirect()->route('companies.index')
|
||||||
|
@ -154,7 +145,7 @@ final class CompaniesController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('companies'.'/'.$company->image);
|
Storage::disk('public')->delete('companies'.'/'.$company->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +155,7 @@ final class CompaniesController extends Controller
|
||||||
->with('success', trans('admin/companies/message.delete.success'));
|
->with('success', trans('admin/companies/message.delete.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show($id)
|
public function show($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', Company::class);
|
$this->authorize('view', Company::class);
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class ComponentCheckinController extends Controller
|
||||||
|
|
||||||
$asset = Asset::find($component_assets->asset_id);
|
$asset = Asset::find($component_assets->asset_id);
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($component, $asset, Auth::user(), $request->input('note'), Carbon::now()));
|
event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
|
||||||
if ($backto == 'asset'){
|
if ($backto == 'asset'){
|
||||||
return redirect()->route('hardware.show', $asset->id)->with('success',
|
return redirect()->route('hardware.show', $asset->id)->with('success',
|
||||||
trans('admin/components/message.checkin.success'));
|
trans('admin/components/message.checkin.success'));
|
||||||
|
|
|
@ -100,14 +100,14 @@ class ComponentCheckoutController extends Controller
|
||||||
$component->asset_id = $request->input('asset_id');
|
$component->asset_id = $request->input('asset_id');
|
||||||
$component->assets()->attach($component->id, [
|
$component->assets()->attach($component->id, [
|
||||||
'component_id' => $component->id,
|
'component_id' => $component->id,
|
||||||
'user_id' => Auth::user(),
|
'user_id' => auth()->user(),
|
||||||
'created_at' => date('Y-m-d H:i:s'),
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
'assigned_qty' => $request->input('assigned_qty'),
|
'assigned_qty' => $request->input('assigned_qty'),
|
||||||
'asset_id' => $request->input('asset_id'),
|
'asset_id' => $request->input('asset_id'),
|
||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($component, $asset, Auth::user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls all actions related to Components for
|
* This class controls all actions related to Components for
|
||||||
|
@ -188,7 +189,7 @@ class ComponentsController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('components/'.$component->image);
|
Storage::disk('public')->delete('components/'.$component->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use App\Models\Component;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ComponentsFilesController extends Controller
|
class ComponentsFilesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -84,7 +85,7 @@ class ComponentsFilesController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::delete('components/'.$log->filename);
|
Storage::delete('components/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ class ComponentsFilesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function show($componentId = null, $fileId = null)
|
public function show($componentId = null, $fileId = null)
|
||||||
{
|
{
|
||||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||||
$component = Component::find($componentId);
|
$component = Component::find($componentId);
|
||||||
|
|
||||||
// the component is valid
|
// the component is valid
|
||||||
|
@ -126,8 +127,8 @@ class ComponentsFilesController extends Controller
|
||||||
$file = 'private_uploads/components/'.$log->filename;
|
$file = 'private_uploads/components/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|
|
@ -4,12 +4,11 @@ namespace App\Http\Controllers\Consumables;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Accessory;
|
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use \Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Support\Facades\Input;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class ConsumableCheckoutController extends Controller
|
class ConsumableCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -20,13 +19,11 @@ class ConsumableCheckoutController extends Controller
|
||||||
* @see ConsumableCheckoutController::store() method that stores the data.
|
* @see ConsumableCheckoutController::store() method that stores the data.
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create($id)
|
public function create($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($consumable = Consumable::with('users')->find($id)) {
|
if ($consumable = Consumable::find($id)) {
|
||||||
|
|
||||||
$this->authorize('checkout', $consumable);
|
$this->authorize('checkout', $consumable);
|
||||||
|
|
||||||
|
@ -71,12 +68,18 @@ class ConsumableCheckoutController extends Controller
|
||||||
|
|
||||||
$this->authorize('checkout', $consumable);
|
$this->authorize('checkout', $consumable);
|
||||||
|
|
||||||
|
// If the quantity is not present in the request or is not a positive integer, set it to 1
|
||||||
|
$quantity = $request->input('qty');
|
||||||
|
if (!isset($quantity) || !ctype_digit((string)$quantity) || $quantity <= 0) {
|
||||||
|
$quantity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure there is at least one available to checkout
|
// Make sure there is at least one available to checkout
|
||||||
if ($consumable->numRemaining() <= 0) {
|
if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) {
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$admin_user = Auth::user();
|
$admin_user = auth()->user();
|
||||||
$assigned_to = e($request->input('assigned_to'));
|
$assigned_to = e($request->input('assigned_to'));
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
|
@ -88,14 +91,15 @@ class ConsumableCheckoutController extends Controller
|
||||||
// Update the consumable data
|
// Update the consumable data
|
||||||
$consumable->assigned_to = e($request->input('assigned_to'));
|
$consumable->assigned_to = e($request->input('assigned_to'));
|
||||||
|
|
||||||
|
for($i = 0; $i < $quantity; $i++){
|
||||||
$consumable->users()->attach($consumable->id, [
|
$consumable->users()->attach($consumable->id, [
|
||||||
'consumable_id' => $consumable->id,
|
'consumable_id' => $consumable->id,
|
||||||
'user_id' => $admin_user->id,
|
'user_id' => $admin_user->id,
|
||||||
'assigned_to' => e($request->input('assigned_to')),
|
'assigned_to' => e($request->input('assigned_to')),
|
||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
// Redirect to the new consumable page
|
// Redirect to the new consumable page
|
||||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success'));
|
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success'));
|
||||||
|
|
|
@ -8,8 +8,10 @@ use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Input;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
use App\Http\Requests\StoreConsumableRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Consumables for
|
* This controller handles all actions related to Consumables for
|
||||||
|
@ -62,7 +64,7 @@ class ConsumablesController extends Controller
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreConsumableRequest $request)
|
||||||
{
|
{
|
||||||
$this->authorize('create', Consumable::class);
|
$this->authorize('create', Consumable::class);
|
||||||
$consumable = new Consumable();
|
$consumable = new Consumable();
|
||||||
|
@ -99,10 +101,8 @@ class ConsumablesController extends Controller
|
||||||
* @param int $consumableId
|
* @param int $consumableId
|
||||||
* @see ConsumablesController::postEdit() method that stores the form data.
|
* @see ConsumablesController::postEdit() method that stores the form data.
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit($consumableId = null)
|
public function edit($consumableId = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
if ($item = Consumable::find($consumableId)) {
|
if ($item = Consumable::find($consumableId)) {
|
||||||
$this->authorize($item);
|
$this->authorize($item);
|
||||||
|
@ -124,7 +124,7 @@ class ConsumablesController extends Controller
|
||||||
* @see ConsumablesController::getEdit() method that stores the form data.
|
* @see ConsumablesController::getEdit() method that stores the form data.
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $consumableId = null)
|
public function update(StoreConsumableRequest $request, $consumableId = null)
|
||||||
{
|
{
|
||||||
if (is_null($consumable = Consumable::find($consumableId))) {
|
if (is_null($consumable = Consumable::find($consumableId))) {
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
|
||||||
|
@ -182,6 +182,7 @@ class ConsumablesController extends Controller
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
|
||||||
}
|
}
|
||||||
$this->authorize($consumable);
|
$this->authorize($consumable);
|
||||||
|
|
||||||
$consumable->delete();
|
$consumable->delete();
|
||||||
// Redirect to the locations management page
|
// Redirect to the locations management page
|
||||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.delete.success'));
|
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.delete.success'));
|
||||||
|
|
|
@ -10,7 +10,7 @@ use App\Models\Consumable;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
class ConsumablesFilesController extends Controller
|
class ConsumablesFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -83,7 +83,7 @@ class ConsumablesFilesController extends Controller
|
||||||
try {
|
try {
|
||||||
Storage::delete('consumables/'.$log->filename);
|
Storage::delete('consumables/'.$log->filename);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ class ConsumablesFilesController extends Controller
|
||||||
$file = 'private_uploads/consumables/'.$log->filename;
|
$file = 'private_uploads/consumables/'.$log->filename;
|
||||||
|
|
||||||
if (Storage::missing($file)) {
|
if (Storage::missing($file)) {
|
||||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||||
\Log::debug('URL should be '.Storage::url($file));
|
Log::debug('URL should be '.Storage::url($file));
|
||||||
|
|
||||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||||
->header('Content-Type', 'text/plain');
|
->header('Content-Type', 'text/plain');
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
@ -35,6 +35,6 @@ abstract class Controller extends BaseController
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
view()->share('signedIn', Auth::check());
|
view()->share('signedIn', Auth::check());
|
||||||
view()->share('user', Auth::user());
|
view()->share('user', auth()->user());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ use App\Models\CustomField;
|
||||||
use App\Models\CustomFieldset;
|
use App\Models\CustomFieldset;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Redirect;
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use \Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Custom Asset Fields for
|
* This controller handles all actions related to Custom Asset Fields for
|
||||||
|
@ -26,10 +27,8 @@ class CustomFieldsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Support\Facades\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index() : View
|
||||||
{
|
{
|
||||||
$this->authorize('view', CustomField::class);
|
$this->authorize('view', CustomField::class);
|
||||||
|
|
||||||
|
@ -46,10 +45,8 @@ class CustomFieldsController extends Controller
|
||||||
* @see CustomFieldsController::storeField()
|
* @see CustomFieldsController::storeField()
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.1.5]
|
* @since [v5.1.5]
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function show()
|
public function show() : RedirectResponse
|
||||||
{
|
{
|
||||||
return redirect()->route('fields.index');
|
return redirect()->route('fields.index');
|
||||||
}
|
}
|
||||||
|
@ -61,10 +58,8 @@ class CustomFieldsController extends Controller
|
||||||
* @see CustomFieldsController::storeField()
|
* @see CustomFieldsController::storeField()
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Support\Facades\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function create(Request $request)
|
public function create(Request $request) : View
|
||||||
{
|
{
|
||||||
$this->authorize('create', CustomField::class);
|
$this->authorize('create', CustomField::class);
|
||||||
$fieldsets = CustomFieldset::get();
|
$fieldsets = CustomFieldset::get();
|
||||||
|
@ -83,10 +78,8 @@ class CustomFieldsController extends Controller
|
||||||
* @see CustomFieldsController::createField()
|
* @see CustomFieldsController::createField()
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function store(CustomFieldRequest $request)
|
public function store(CustomFieldRequest $request) : RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('create', CustomField::class);
|
$this->authorize('create', CustomField::class);
|
||||||
|
|
||||||
|
@ -145,10 +138,8 @@ class CustomFieldsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function deleteFieldFromFieldset($field_id, $fieldset_id)
|
public function deleteFieldFromFieldset($field_id, $fieldset_id) : RedirectResponse
|
||||||
{
|
{
|
||||||
$field = CustomField::find($field_id);
|
$field = CustomField::find($field_id);
|
||||||
|
|
||||||
|
@ -177,10 +168,8 @@ class CustomFieldsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||||
* @since [v1.8]
|
* @since [v1.8]
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function destroy($field_id)
|
public function destroy($field_id) : RedirectResponse
|
||||||
{
|
{
|
||||||
if ($field = CustomField::find($field_id)) {
|
if ($field = CustomField::find($field_id)) {
|
||||||
$this->authorize('delete', $field);
|
$this->authorize('delete', $field);
|
||||||
|
@ -203,10 +192,8 @@ class CustomFieldsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return \Illuminate\Support\Facades\View
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
if ($field = CustomField::find($id)) {
|
if ($field = CustomField::find($id)) {
|
||||||
|
|
||||||
|
@ -242,7 +229,7 @@ class CustomFieldsController extends Controller
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function update(CustomFieldRequest $request, $id)
|
public function update(CustomFieldRequest $request, $id) : RedirectResponse
|
||||||
{
|
{
|
||||||
$field = CustomField::find($id);
|
$field = CustomField::find($id);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue