mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-25 05:34:06 -08:00
Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
3855b74161
157
.env.docker
Normal file
157
.env.docker
Normal file
|
@ -0,0 +1,157 @@
|
|||
# --------------------------------------------
|
||||
# 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
|
||||
|
||||
# --------------------------------------------
|
||||
# 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: LOGIN THROTTLING
|
||||
# --------------------------------------------
|
||||
LOGIN_MAX_ATTEMPTS=5
|
||||
LOGIN_LOCKOUT_DURATION=60
|
||||
RESET_PASSWORD_LINK_EXPIRES=900
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: MISC
|
||||
# --------------------------------------------
|
||||
APP_LOG=stderr
|
||||
APP_LOG_MAX_FILES=10
|
||||
APP_LOCKED=false
|
||||
APP_CIPHER=AES-256-CBC
|
||||
GOOGLE_MAPS_API=
|
||||
LDAP_MEM_LIM=500M
|
||||
LDAP_TIME_LIM=600
|
49
.github/workflows/codacy-analysis.yml
vendored
Normal file
49
.github/workflows/codacy-analysis.yml
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
# This workflow checks out code, performs a Codacy security scan
|
||||
# and integrates the results with the
|
||||
# GitHub Advanced Security code scanning feature. For more information on
|
||||
# the Codacy security scan action usage and parameters, see
|
||||
# https://github.com/codacy/codacy-analysis-cli-action.
|
||||
# For more information on Codacy Analysis CLI in general, see
|
||||
# https://github.com/codacy/codacy-analysis-cli.
|
||||
|
||||
name: Codacy Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '36 23 * * 3'
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
name: Codacy Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@1.1.0
|
||||
with:
|
||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||
# You can also omit the token and run the tools that support default configurations
|
||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
verbose: true
|
||||
output: results.sarif
|
||||
format: sarif
|
||||
# Adjust severity of non-security issues
|
||||
gh-code-scanning-compat: true
|
||||
# Force 0 exit code to allow SARIF file generation
|
||||
# This will handover control about PR rejection to the GitHub side
|
||||
max-allowed-issues: 2147483647
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF results file
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: results.sarif
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -48,7 +48,7 @@ tests/_support/_generated/*
|
|||
/npm-debug.log
|
||||
/storage/oauth-private.key
|
||||
/storage/oauth-public.key
|
||||
|
||||
logs/*
|
||||
*.cache
|
||||
|
||||
.vagrant
|
||||
|
|
102
Dockerfile.fpm-alpine
Normal file
102
Dockerfile.fpm-alpine
Normal file
|
@ -0,0 +1,102 @@
|
|||
ARG ENVIRONMENT=production
|
||||
ARG SNIPEIT_RELEASE=5.1.3
|
||||
ARG PHP_VERSION=7.4.16
|
||||
ARG PHP_ALPINE_VERSION=3.13
|
||||
ARG COMPOSER_VERSION=2.0.11
|
||||
|
||||
# Cannot use arguments with 'COPY --from' workaround
|
||||
# https://github.com/moby/moby/issues/34482#issuecomment-454716952
|
||||
FROM composer:${COMPOSER_VERSION} AS composer
|
||||
|
||||
# Final stage
|
||||
FROM php:${PHP_VERSION}-fpm-alpine${PHP_ALPINE_VERSION} AS source
|
||||
LABEL maintainer="Mateus Villar <mromeravillar@gmail.com>"
|
||||
|
||||
ARG PACKAGES="\
|
||||
mysql-client \
|
||||
"
|
||||
ARG DEV_PACKAGES="\
|
||||
git \
|
||||
"
|
||||
ARG ENVIRONMENT
|
||||
ENV ENVIRONMENT ${ENVIRONMENT}
|
||||
ARG SNIPEIT_RELEASE
|
||||
ENV SNIPEIT_RELEASE ${SNIPEIT_RELEASE}
|
||||
|
||||
# Cribbed from wordpress-fpm-alpine image
|
||||
# set recommended PHP.ini settings
|
||||
# see https://secure.php.net/manual/en/opcache.installation.php
|
||||
RUN set -eux; \
|
||||
docker-php-ext-enable opcache; \
|
||||
{ \
|
||||
echo 'opcache.memory_consumption=128'; \
|
||||
echo 'opcache.interned_strings_buffer=8'; \
|
||||
echo 'opcache.max_accelerated_files=4000'; \
|
||||
echo 'opcache.revalidate_freq=2'; \
|
||||
echo 'opcache.fast_shutdown=1'; \
|
||||
} > /usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||
# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging
|
||||
RUN { \
|
||||
# https://www.php.net/manual/en/errorfunc.constants.php
|
||||
# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670
|
||||
echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \
|
||||
echo 'display_errors = Off'; \
|
||||
echo 'display_startup_errors = Off'; \
|
||||
echo 'log_errors = On'; \
|
||||
echo 'error_log = /dev/stderr'; \
|
||||
echo 'log_errors_max_len = 1024'; \
|
||||
echo 'ignore_repeated_errors = On'; \
|
||||
echo 'ignore_repeated_source = Off'; \
|
||||
echo 'html_errors = Off'; \
|
||||
} > /usr/local/etc/php/conf.d/error-logging.ini
|
||||
|
||||
# Install php extensions inside docker containers easily
|
||||
# https://github.com/mlocati/docker-php-extension-installer
|
||||
COPY --from=mlocati/php-extension-installer:1.2.19 /usr/bin/install-php-extensions /usr/local/bin/
|
||||
RUN set -eux; \
|
||||
install-php-extensions \
|
||||
bcmath \
|
||||
gd \
|
||||
ldap \
|
||||
mysqli \
|
||||
pdo_mysql \
|
||||
zip; \
|
||||
rm -f /usr/local/bin/install-php-extensions; \
|
||||
# Install prerequisites packages
|
||||
apk add --no-cache \
|
||||
${PACKAGES};
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/local/bin
|
||||
ARG COMPOSER_ALLOW_SUPERUSER=1
|
||||
RUN set -eux; \
|
||||
# Download and extract snipeit tarball
|
||||
curl -o snipeit.tar.gz -fL "https://github.com/snipe/snipe-it/archive/v$SNIPEIT_RELEASE.tar.gz"; \
|
||||
tar -xzf snipeit.tar.gz --strip-components=1 -C /var/www/html/; \
|
||||
rm snipeit.tar.gz; \
|
||||
# Install composer php dependencies
|
||||
if [ "$ENVIRONMENT" = "production" ]; then \
|
||||
echo "production enviroment detected!"; \
|
||||
composer update \
|
||||
--no-cache \
|
||||
--no-dev \
|
||||
--optimize-autoloader \
|
||||
--working-dir=/var/www/html; \
|
||||
else \
|
||||
echo "development enviroment detected!"; \
|
||||
apk add --no-cache \
|
||||
${DEV_PACKAGES}; \
|
||||
composer update \
|
||||
--no-cache \
|
||||
--prefer-source \
|
||||
--optimize-autoloader \
|
||||
--working-dir=/var/www/html; \
|
||||
fi; \
|
||||
rm -f /usr/local/bin/composer; \
|
||||
chown -R www-data:www-data /var/www/html;
|
||||
|
||||
VOLUME [ "/var/lib/snipeit" ]
|
||||
|
||||
COPY --chown=www-data:www-data docker/docker-secrets.env /var/www/html/.env
|
||||
COPY --chmod=655 docker/docker-entrypoint.sh /usr/local/bin/docker-snipeit-entrypoint
|
||||
ENTRYPOINT [ "/usr/local/bin/docker-snipeit-entrypoint" ]
|
||||
CMD [ "/usr/local/bin/docker-php-entrypoint", "php-fpm" ]
|
|
@ -572,7 +572,12 @@ class AssetsController extends Controller
|
|||
*
|
||||
* This needs a LOT of love. It's done very inelegantly right now, and there are
|
||||
* a ton of optimizations that could (and should) be done.
|
||||
*
|
||||
*
|
||||
* Updated to respect checkin dates:
|
||||
* No checkin column, assume all items are checked in (todays date)
|
||||
* Checkin date in the past, update history.
|
||||
* Checkin date in future or empty, check the item out to the user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.3]
|
||||
* @return View
|
||||
|
@ -589,6 +594,8 @@ class AssetsController extends Controller
|
|||
}
|
||||
$csv = Reader::createFromPath($request->file('user_import_csv'));
|
||||
$csv->setHeaderOffset(0);
|
||||
$header = $csv->getHeader();
|
||||
$isCheckinHeaderExplicit = in_array("checkin date", (array_map('strtolower', $header)));
|
||||
$results = $csv->getRecords();
|
||||
$item = array();
|
||||
$status = array();
|
||||
|
@ -603,8 +610,19 @@ class AssetsController extends Controller
|
|||
}
|
||||
$batch_counter = count($item[$asset_tag]);
|
||||
$item[$asset_tag][$batch_counter]['checkout_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkout date"))->format('Y-m-d H:i:s');
|
||||
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkin date"))->format('Y-m-d H:i:s');
|
||||
\Log::debug($item[$asset_tag][$batch_counter]['checkin_date']);
|
||||
|
||||
if ($isCheckinHeaderExplicit){
|
||||
//checkin date not empty, assume past transaction or future checkin date (expected)
|
||||
if (!empty(Helper::array_smart_fetch($row, "checkin date"))) {
|
||||
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkin date"))->format('Y-m-d H:i:s');
|
||||
} else {
|
||||
$item[$asset_tag][$batch_counter]['checkin_date'] = '';
|
||||
}
|
||||
} else {
|
||||
//checkin header missing, assume data is unavailable and make checkin date explicit (now) so we don't encounter invalid state.
|
||||
$item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(now())->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$item[$asset_tag][$batch_counter]['asset_tag'] = Helper::array_smart_fetch($row, "asset tag");
|
||||
$item[$asset_tag][$batch_counter]['name'] = Helper::array_smart_fetch($row, "name");
|
||||
$item[$asset_tag][$batch_counter]['email'] = Helper::array_smart_fetch($row, "email");
|
||||
|
@ -632,16 +650,24 @@ class AssetsController extends Controller
|
|||
$user_query .= ', or on username '.$firstname['username'];
|
||||
}
|
||||
if ($request->input('match_email')=='1') {
|
||||
if ($item[$asset_tag][$batch_counter]['email']=='') {
|
||||
if ($item[$asset_tag][$batch_counter]['name']=='') {
|
||||
$item[$asset_tag][$batch_counter]['username'][] = $user_email = User::generateEmailFromFullName($item[$asset_tag][$batch_counter]['name']);
|
||||
$user->orWhere('username', '=', $user_email);
|
||||
$user_query .= ', or on username '.$user_email;
|
||||
}
|
||||
}
|
||||
if ($request->input('match_username') == '1'){
|
||||
// Added #8825: add explicit username lookup
|
||||
$raw_username = $item[$asset_tag][$batch_counter]['name'];
|
||||
$user->orWhere('username', '=', $raw_username);
|
||||
$user_query .= ', or on username ' . $raw_username;
|
||||
}
|
||||
|
||||
// A matching user was found
|
||||
if ($user = $user->first()) {
|
||||
$item[$asset_tag][$batch_counter]['checkedout_to'] = $user->id;
|
||||
//$user is now matched user from db
|
||||
$item[$asset_tag][$batch_counter]['user_id'] = $user->id;
|
||||
|
||||
Actionlog::firstOrCreate(array(
|
||||
'item_id' => $asset->id,
|
||||
'item_type' => Asset::class,
|
||||
|
@ -652,14 +678,44 @@ class AssetsController extends Controller
|
|||
'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'],
|
||||
'action_type' => 'checkout',
|
||||
));
|
||||
$asset->assigned_to = $user->id;
|
||||
|
||||
$checkin_date = $item[$asset_tag][$batch_counter]['checkin_date'];
|
||||
|
||||
if ($isCheckinHeaderExplicit) {
|
||||
|
||||
//if checkin date header exists, assume that empty or future date is still checked out
|
||||
//if checkin is before todays date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items is checked out
|
||||
|
||||
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date))
|
||||
) {
|
||||
//only do this if item is checked out
|
||||
$asset->assigned_to = $user->id;
|
||||
$asset->assigned_type = User::class;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($checkin_date)) {
|
||||
//only make a checkin there is a valid checkin date or we created one on import.
|
||||
Actionlog::firstOrCreate(array(
|
||||
'item_id' =>
|
||||
$item[$asset_tag][$batch_counter]['asset_id'],
|
||||
'item_type' => Asset::class,
|
||||
'user_id' => Auth::user()->id,
|
||||
'note' => 'Checkin imported by ' . Auth::user()->present()->fullName() . ' from history importer',
|
||||
'target_id' => null,
|
||||
'created_at' => $checkin_date,
|
||||
'action_type' => 'checkin'
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
if ($asset->save()) {
|
||||
$status['success'][]['asset'][$asset_tag]['msg'] = 'Asset successfully matched for '.Helper::array_smart_fetch($row, "name").$user_query.' on '.$item[$asset_tag][$batch_counter]['checkout_date'];
|
||||
} else {
|
||||
$status['error'][]['asset'][$asset_tag]['msg'] = 'Asset and user was matched but could not be saved.';
|
||||
}
|
||||
} else {
|
||||
$item[$asset_tag][$batch_counter]['checkedout_to'] = null;
|
||||
$item[$asset_tag][$batch_counter]['user_id'] = null;
|
||||
$status['error'][]['user'][Helper::array_smart_fetch($row, "name")]['msg'] = 'User does not exist so no checkin log was created.';
|
||||
}
|
||||
} else {
|
||||
|
@ -668,31 +724,6 @@ class AssetsController extends Controller
|
|||
}
|
||||
}
|
||||
}
|
||||
// Loop through and backfill the checkins
|
||||
foreach ($item as $key => $asset_batch) {
|
||||
$total_in_batch = count($asset_batch);
|
||||
for ($x = 0; $x < $total_in_batch; $x++) {
|
||||
$next = $x + 1;
|
||||
// Only do this if a matching user was found
|
||||
if ((array_key_exists('checkedout_to', $asset_batch[$x])) && ($asset_batch[$x]['checkedout_to']!='')) {
|
||||
if (($total_in_batch > 1) && ($x < $total_in_batch) && (array_key_exists($next, $asset_batch))) {
|
||||
$checkin_date = Carbon::parse($asset_batch[$next]['checkin_date'])->format('Y-m-d H:i:s');
|
||||
$asset_batch[$x]['real_checkin'] = $checkin_date;
|
||||
\Log::debug($asset_batch[$next]['checkin_date']);
|
||||
\Log::debug($checkin_date);
|
||||
Actionlog::firstOrCreate(array(
|
||||
'item_id' => $asset_batch[$x]['asset_id'],
|
||||
'item_type' => Asset::class,
|
||||
'user_id' => Auth::user()->id,
|
||||
'note' => 'Checkin imported by ' . Auth::user()->present()->fullName() . ' from history importer',
|
||||
'target_id' => null,
|
||||
'created_at' => $checkin_date,
|
||||
'action_type' => 'checkin'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return view('hardware/history')->with('status', $status);
|
||||
}
|
||||
|
||||
|
|
|
@ -140,8 +140,9 @@ class LoginController extends Controller
|
|||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function loginViaLdap(LdapAd $ldap, Request $request): User
|
||||
private function loginViaLdap(Request $request): User
|
||||
{
|
||||
$ldap = \App::make( LdapAd::class);
|
||||
try {
|
||||
return $ldap->ldapLogin($request->input('username'), $request->input('password'));
|
||||
} catch (\Exception $ex) {
|
||||
|
|
|
@ -40,6 +40,24 @@ class CustomFieldsController extends Controller
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Just redirect the user back if they try to view the details of a field.
|
||||
* We already show those details on the listing page.
|
||||
*
|
||||
* @see CustomFieldsController::storeField()
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.1.5]
|
||||
* @return Redirect
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
|
||||
public function show()
|
||||
{
|
||||
return redirect()->route("fields.index");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a view with a form to create a new custom field.
|
||||
*
|
||||
|
@ -133,16 +151,19 @@ class CustomFieldsController extends Controller
|
|||
*/
|
||||
public function destroy($field_id)
|
||||
{
|
||||
$field = CustomField::find($field_id);
|
||||
if ($field = CustomField::find($field_id)) {
|
||||
|
||||
$this->authorize('delete', $field);
|
||||
$this->authorize('delete', $field);
|
||||
|
||||
if ($field->fieldset->count()>0) {
|
||||
return redirect()->back()->withErrors(['message' => "Field is in-use"]);
|
||||
if (($field->fieldset) && ($field->fieldset->count() > 0)) {
|
||||
return redirect()->back()->withErrors(['message' => "Field is in-use"]);
|
||||
}
|
||||
$field->delete();
|
||||
return redirect()->route("fields.index")
|
||||
->with("success", trans('admin/custom_fields/message.field.delete.success'));
|
||||
}
|
||||
$field->delete();
|
||||
return redirect()->route("fields.index")
|
||||
->with("success", trans('admin/custom_fields/message.field.delete.success'));
|
||||
|
||||
return redirect()->back()->withErrors(['message' => "Field does not exist"]);
|
||||
}
|
||||
|
||||
|
||||
|
|
48
docker-compose.yml
Normal file
48
docker-compose.yml
Normal file
|
@ -0,0 +1,48 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
snipeit:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.alpine
|
||||
container_name: snipeit
|
||||
ports:
|
||||
- 8000:80
|
||||
volumes:
|
||||
- ./logs:/var/www/html/storage/logs
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
env_file:
|
||||
- .env.docker
|
||||
networks:
|
||||
- snipeit-backend
|
||||
|
||||
mariadb:
|
||||
image: mariadb:latest
|
||||
volumes:
|
||||
- db:/var/lib/mysql
|
||||
env_file:
|
||||
- .env.docker
|
||||
networks:
|
||||
- snipeit-backend
|
||||
|
||||
redis:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- snipeit-backend
|
||||
|
||||
mailhog:
|
||||
image: mailhog/mailhog:latest
|
||||
ports:
|
||||
# - 1025:1025
|
||||
- 8025:8025
|
||||
networks:
|
||||
- snipeit-backend
|
||||
|
||||
|
||||
volumes:
|
||||
db: {}
|
||||
|
||||
networks:
|
||||
snipeit-backend: {}
|
119
docker/docker-entrypoint.sh
Executable file
119
docker/docker-entrypoint.sh
Executable file
|
@ -0,0 +1,119 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eo pipefail;
|
||||
|
||||
# Cribbed from nextcloud docker official repo
|
||||
# https://github.com/nextcloud/docker/blob/master/docker-entrypoint.sh
|
||||
# usage: file_env VAR [DEFAULT]
|
||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
||||
file_env() {
|
||||
local var="$1"
|
||||
local fileVar="${var}_FILE"
|
||||
local def="${2:-}"
|
||||
local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
|
||||
local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
|
||||
if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
|
||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "${varValue}" ]; then
|
||||
export "$var"="${varValue}"
|
||||
elif [ -n "${fileVarValue}" ]; then
|
||||
export "$var"="$(cat "${fileVarValue}")"
|
||||
elif [ -n "${def}" ]; then
|
||||
export "$var"="$def"
|
||||
fi
|
||||
unset "$fileVar"
|
||||
}
|
||||
|
||||
# Add docker secrets support for the variables below:
|
||||
file_env APP_KEY
|
||||
file_env DB_HOST
|
||||
file_env DB_PORT
|
||||
file_env DB_DATABASE
|
||||
file_env DB_USERNAME
|
||||
file_env DB_PASSWORD
|
||||
file_env REDIS_HOST
|
||||
file_env REDIS_PASSWORD
|
||||
file_env REDIS_PORT
|
||||
file_env MAIL_HOST
|
||||
file_env MAIL_PORT
|
||||
file_env MAIL_USERNAME
|
||||
file_env MAIL_PASSWORD
|
||||
|
||||
echo [INFO docker entrypoint] Start script execution
|
||||
|
||||
# Generate new app key if none is provided
|
||||
if [ -z "$APP_KEY" -a -z "$APP_KEY_FILE" ]
|
||||
then
|
||||
echo "Please re-run this container with an environment variable \$APP_KEY"
|
||||
echo "An example APP_KEY you could use is: "
|
||||
php artisan key:generate --show
|
||||
exit
|
||||
fi
|
||||
|
||||
# Directory configuration
|
||||
rm -rf \
|
||||
"/var/www/html/storage/private_uploads" \
|
||||
"/var/www/html/public/uploads" \
|
||||
"/var/www/html/storage/app/backups"
|
||||
|
||||
# Create data directories
|
||||
for dir in \
|
||||
'data/private_uploads' \
|
||||
'data/uploads/accessories' \
|
||||
'data/uploads/avatars' \
|
||||
'data/uploads/barcodes' \
|
||||
'data/uploads/categories' \
|
||||
'data/uploads/companies' \
|
||||
'data/uploads/components' \
|
||||
'data/uploads/consumables' \
|
||||
'data/uploads/departments' \
|
||||
'data/uploads/locations' \
|
||||
'data/uploads/manufacturers' \
|
||||
'data/uploads/models' \
|
||||
'data/uploads/suppliers' \
|
||||
'dumps' \
|
||||
'keys'
|
||||
do
|
||||
[ ! -d "/var/lib/snipeit/$dir" ] && mkdir -p "/var/lib/snipeit/$dir"
|
||||
done
|
||||
|
||||
# Sync /var/lib/snipeit (docker volume) with /var/www/html directory
|
||||
ln -fs \
|
||||
"/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads"
|
||||
ln -fs \
|
||||
"/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads"
|
||||
ln -fs \
|
||||
"/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups"
|
||||
ln -fs \
|
||||
"/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key"
|
||||
ln -fs \
|
||||
"/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key"
|
||||
|
||||
# If the Oauth DB files are not present copy the vendor files over to the db migrations
|
||||
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
|
||||
then
|
||||
cp -a /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
|
||||
fi
|
||||
|
||||
# Create laravel log file
|
||||
touch /var/www/html/storage/logs/laravel.log
|
||||
# Add correct permissions for files and directories
|
||||
chown www-data:www-data /var/www/html/storage/logs/laravel.log
|
||||
chown -R www-data:www-data \
|
||||
/var/lib/snipeit/data \
|
||||
/var/lib/snipeit/dumps \
|
||||
/var/lib/snipeit/keys
|
||||
|
||||
# Migrate/create database
|
||||
php artisan migrate --force
|
||||
# Clear cache files
|
||||
php artisan config:clear
|
||||
php artisan config:cache
|
||||
|
||||
echo [INFO docker entrypoint] End script execution
|
||||
|
||||
exec "$@"
|
54
docker/docker-secrets.env
Normal file
54
docker/docker-secrets.env
Normal file
|
@ -0,0 +1,54 @@
|
|||
# --------------------------------------------
|
||||
# REQUIRED: BASIC APP SETTINGS
|
||||
# --------------------------------------------
|
||||
#APP_ENV=develop
|
||||
#APP_DEBUG=false
|
||||
#APP_KEY=Change_this_key_or_snipe_will_get_ya
|
||||
#APP_URL=http://127.0.0.1:32782
|
||||
#APP_TIMEZONE=US/Pacific
|
||||
#APP_LOCALE=en
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: DATABASE SETTINGS
|
||||
# --------------------------------------------
|
||||
DB_CONNECTION=mysql
|
||||
DB_PREFIX=null
|
||||
DB_DUMP_PATH='/usr/bin'
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||
# --------------------------------------------
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_ENCRYPTION=${MAIL_ENV_ENCRYPTION}
|
||||
MAIL_FROM_ADDR=${MAIL_ENV_FROM_ADDR}
|
||||
MAIL_FROM_NAME=${MAIL_ENV_FROM_NAME}
|
||||
MAIL_REPLYTO_ADDR=${MAIL_ENV_FROM_ADDR}
|
||||
MAIL_REPLYTO_NAME=${MAIL_ENV_FROM_NAME}
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: IMAGE LIBRARY
|
||||
# This should be gd or imagick
|
||||
# --------------------------------------------
|
||||
IMAGE_LIB=gd
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SESSION SETTINGS
|
||||
# --------------------------------------------
|
||||
SESSION_LIFETIME=12000
|
||||
EXPIRE_ON_CLOSE=false
|
||||
ENCRYPT=false
|
||||
COOKIE_NAME=snipeit_session
|
||||
COOKIE_DOMAIN=null
|
||||
SECURE_COOKIES=false
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: CACHE SETTINGS
|
||||
# --------------------------------------------
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
QUEUE_DRIVER=sync
|
15
package-lock.json
generated
15
package-lock.json
generated
|
@ -7030,6 +7030,12 @@
|
|||
"omggif": "1.0.7",
|
||||
"promise-polyfill": "8.1.0",
|
||||
"stackblur-canvas": "2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"file-saver": {
|
||||
"version": "git+ssh://git@github.com/eligrey/FileSaver.js.git#e865e37af9f9947ddcced76b549e27dc45c1cb2e",
|
||||
"from": "git+ssh://git@github.com/eligrey/FileSaver.js.git#e865e37af9f9947ddcced76b549e27dc45c1cb2e"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stackblur-canvas": {
|
||||
|
@ -8887,7 +8893,8 @@
|
|||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
|
@ -12214,9 +12221,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"ssri": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
|
||||
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
|
||||
"integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"figgy-pudding": "^3.5.1"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
{{ trans('admin/categories/general.asset_categories') }}
|
||||
{{ trans('general.categories') }}
|
||||
@parent
|
||||
@stop
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
@extends('layouts/default')
|
||||
@extends('layouts/default', [
|
||||
'helpText' => trans('admin/custom_fields/general.about_fieldsets_text'),
|
||||
'helpPosition' => 'right',
|
||||
])
|
||||
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
|
@ -10,7 +14,7 @@
|
|||
|
||||
@can('view', \App\Models\CustomFieldset::class)
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-default">
|
||||
|
||||
<div class="box-header with-border">
|
||||
|
@ -83,12 +87,9 @@
|
|||
</div><!-- /.box-body -->
|
||||
</div><!-- /.box.box-default -->
|
||||
|
||||
</div> <!-- .col-md-9-->
|
||||
<!-- side address column -->
|
||||
<div class="col-md-3">
|
||||
<h2>{{ trans('admin/custom_fields/general.about_fieldsets_title') }}</h2>
|
||||
<p>{{ trans('admin/custom_fields/general.about_fieldsets_text') }} </p>
|
||||
</div>
|
||||
</div> <!-- .col-md-12-->
|
||||
|
||||
|
||||
</div> <!-- .row-->
|
||||
@endcan
|
||||
@can('view', \App\Models\CustomField::class)
|
||||
|
|
|
@ -64,10 +64,9 @@
|
|||
Upload a CSV that contains asset history. The assets and users MUST already exist in the system, or they will be skipped. Matching assets for history import happens against the asset tag. We will try to find a matching user based on the user's name you provide, and the criteria you select below. If you do not select any criteria below, it will simply try to match on the username format you configured in the Admin > General Settings.
|
||||
</p>
|
||||
|
||||
<p>Fields included in the CSV must match the headers: <strong>Asset Tag, Checkout Date, Checkin Date, Name</strong>. Any additional fields will be ignored. </p>
|
||||
<p>Fields included in the CSV must match the headers: <strong>Asset Tag, Name, Checkout Date, Checkin Date</strong>. Any additional fields will be ignored. </p>
|
||||
|
||||
|
||||
<p><strong>History should be ordered by date in ascending order.</strong></p>
|
||||
<p>Checkin Date: blank or future checkin dates will checkout items to associated user. Excluding the Checkin Date column will create a checkin date with todays date.</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="first_name" class="col-sm-3 control-label">{{ trans('admin/users/general.usercsv') }}</label>
|
||||
|
@ -118,6 +117,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Match username -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2">
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
{{ Form::checkbox('match_username', '1', Request::old('match_username')) }} Try to match users by username
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
@extends('layouts/default')
|
||||
@extends('layouts/default', [
|
||||
'helpText' => trans('admin/statuslabels/table.info') ,
|
||||
'helpPosition' => 'right',
|
||||
])
|
||||
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
|
@ -60,7 +64,6 @@
|
|||
<!-- side address column -->
|
||||
<div class="col-md-3">
|
||||
<h2>{{ trans('admin/statuslabels/table.about') }}</h2>
|
||||
<p>{{ trans('admin/statuslabels/table.info') }}</p>
|
||||
|
||||
<div class="box box-success">
|
||||
<div class="box-body">
|
||||
|
|
Loading…
Reference in a new issue