diff --git a/.all-contributorsrc b/.all-contributorsrc index 790cc0ff94..0790d4ee16 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1651,6 +1651,186 @@ "code" ] }, + { + "login": "jwhulette", + "name": "Wes Hulette", + "avatar_url": "https://avatars1.githubusercontent.com/u/4930051?v=4", + "profile": "http://macfoo.wordpress.com/", + "contributions": [ + "code" + ] + }, + { + "login": "patrict", + "name": "patrict", + "avatar_url": "https://avatars0.githubusercontent.com/u/8134591?v=4", + "profile": "https://github.com/patrict", + "contributions": [ + "code" + ] + }, + { + "login": "VELIKII-DIVAN", + "name": "Dmitriy Minaev", + "avatar_url": "https://avatars3.githubusercontent.com/u/2611616?v=4", + "profile": "https://github.com/VELIKII-DIVAN", + "contributions": [ + "code" + ] + }, + { + "login": "liquidhorse", + "name": "liquidhorse", + "avatar_url": "https://avatars0.githubusercontent.com/u/5132245?v=4", + "profile": "https://github.com/liquidhorse", + "contributions": [ + "code" + ] + }, + { + "login": "Seldaek", + "name": "Jordi Boggiano", + "avatar_url": "https://avatars1.githubusercontent.com/u/183678?v=4", + "profile": "https://seld.be/", + "contributions": [ + "code" + ] + }, + { + "login": "inietov", + "name": "Ivan Nieto", + "avatar_url": "https://avatars0.githubusercontent.com/u/653557?v=4", + "profile": "https://github.com/inietov", + "contributions": [ + "code" + ] + }, + { + "login": "benrubson", + "name": "Ben RUBSON", + "avatar_url": "https://avatars2.githubusercontent.com/u/6764151?v=4", + "profile": "https://github.com/benrubson", + "contributions": [ + "code" + ] + }, + { + "login": "NMathar", + "name": "NMathar", + "avatar_url": "https://avatars2.githubusercontent.com/u/8554558?v=4", + "profile": "https://github.com/NMathar", + "contributions": [ + "code" + ] + }, + { + "login": "smb", + "name": "Steffen", + "avatar_url": "https://avatars1.githubusercontent.com/u/139566?v=4", + "profile": "https://github.com/smb", + "contributions": [ + "code" + ] + }, + { + "login": "Sxderp", + "name": "Sxderp", + "avatar_url": "https://avatars0.githubusercontent.com/u/6609453?v=4", + "profile": "https://github.com/Sxderp", + "contributions": [ + "code" + ] + }, + { + "login": "fanta8897", + "name": "fanta8897", + "avatar_url": "https://avatars1.githubusercontent.com/u/4807843?v=4", + "profile": "https://github.com/fanta8897", + "contributions": [ + "code" + ] + }, + { + "login": "andreybolonin", + "name": "Andrey Bolonin", + "avatar_url": "https://avatars2.githubusercontent.com/u/2576509?v=4", + "profile": "https://andreybolonin.com/phpconsulting/", + "contributions": [ + "code" + ] + }, + { + "login": "shinayoshi", + "name": "shinayoshi", + "avatar_url": "https://avatars3.githubusercontent.com/u/2173307?v=4", + "profile": "http://www.shinayoshi.net/", + "contributions": [ + "code" + ] + }, + { + "login": "reuser", + "name": "Hubert", + "avatar_url": "https://avatars3.githubusercontent.com/u/2130159?v=4", + "profile": "https://github.com/reuser", + "contributions": [ + "code" + ] + }, + { + "login": "KeenRivals", + "name": "KeenRivals", + "avatar_url": "https://avatars0.githubusercontent.com/u/6865789?v=4", + "profile": "https://brashear.me", + "contributions": [ + "code" + ] + }, + { + "login": "omyno", + "name": "omyno", + "avatar_url": "https://avatars3.githubusercontent.com/u/2902513?v=4", + "profile": "https://github.com/omyno", + "contributions": [ + "code" + ] + }, + { + "login": "jackka", + "name": "Evgeny", + "avatar_url": "https://avatars1.githubusercontent.com/u/6271335?v=4", + "profile": "https://github.com/jackka", + "contributions": [ + "code" + ] + }, + { + "login": "colin-campbell", + "name": "Colin Campbell", + "avatar_url": "https://avatars2.githubusercontent.com/u/1169963?v=4", + "profile": "https://digitalist.se", + "contributions": [ + "code" + ] + }, + { + "login": "lubo", + "name": "Ľubomír Kučera", + "avatar_url": "https://avatars3.githubusercontent.com/u/2872098?v=4", + "profile": "https://github.com/lubo", + "contributions": [ + "code" + ] + }, + { + "login": "Mezzle", + "name": "Martin Meredith", + "avatar_url": "https://avatars3.githubusercontent.com/u/570639?v=4", + "profile": "https://www.sourceguru.net", + "contributions": [ + "code" + ] + }, { "login": "timothyfarmer", "name": "Tim Farmer", @@ -1724,10 +1904,37 @@ ] }, { - "login": "alek13", - "name": "Alexander Chibrikin", - "avatar_url": "https://avatars2.githubusercontent.com/u/1972329?v=4", - "profile": "http://phpprofi.ru/", + "login": "johnson-yi", + "name": "johnson-yi", + "avatar_url": "https://avatars1.githubusercontent.com/u/63399474?v=4", + "profile": "https://github.com/johnson-yi", + "contributions": [ + "code" + ] + }, + { + "login": "sanjay900", + "name": "Sanjay Govind", + "avatar_url": "https://avatars1.githubusercontent.com/u/1862720?v=4", + "profile": "https://tangentmc.net", + "contributions": [ + "code" + ] + }, + { + "login": "PeterUpfold", + "name": "Peter Upfold", + "avatar_url": "https://avatars0.githubusercontent.com/u/1255375?v=4", + "profile": "https://peter.upfold.org.uk/", + "contributions": [ + "code" + ] + }, + { + "login": "jbiel", + "name": "Jared Biel", + "avatar_url": "https://avatars2.githubusercontent.com/u/961717?v=4", + "profile": "https://github.com/jbiel", "contributions": [ "code" ] diff --git a/.dockerignore b/.dockerignore index 23ec116755..89521f1d96 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,13 @@ .git +.github +.gitattributes +.gitignore .dockerignore app/storage/logs/* app/storage/views/* vendor/* +storage/framework/cache/* +node_modules +.vagrant +.idea + diff --git a/.env.example b/.env.example index 4ec2ee6aab..b85385d559 100644 --- a/.env.example +++ b/.env.example @@ -9,6 +9,12 @@ 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 # -------------------------------------------- @@ -95,12 +101,24 @@ MEMCACHED_HOST=null MEMCACHED_PORT=null # -------------------------------------------- -# OPTIONAL: AWS S3 SETTINGS +# OPTIONAL: PUBLIC S3 Settings # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null -AWS_BUCKET=null +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 @@ -114,7 +132,6 @@ LOGIN_LOCKOUT_DURATION=60 APP_LOG=single APP_LOG_MAX_FILES=10 APP_LOCKED=false -FILESYSTEM_DISK=local APP_CIPHER=AES-256-CBC GOOGLE_MAPS_API= BACKUP_ENV=true diff --git a/.env.testing b/.env.testing index f84dd82e9f..980f24f09e 100644 --- a/.env.testing +++ b/.env.testing @@ -40,10 +40,12 @@ IMAGE_LIB=gd # -------------------------------------------- # OPTIONAL: AWS S3 SETTINGS # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null +AWS_SECRET_ACCESS_KEY=null +AWS_ACCESS_KEY_ID=null +AWS_DEFAULT_REGION=null AWS_BUCKET=null +AWS_BUCKET_ROOT=null +AWS_URL=null # -------------------------------------------- diff --git a/.env.testing-ci b/.env.testing-ci index b12a99d442..a39cb5976c 100644 --- a/.env.testing-ci +++ b/.env.testing-ci @@ -2,7 +2,7 @@ # REQUIRED: BASIC APP SETTINGS # -------------------------------------------- APP_ENV=testing-ci -APP_DEBUG=true +APP_DEBUG=false APP_KEY=ChangeMe APP_URL=http://localhost:8000 APP_TIMEZONE='US/Pacific' @@ -40,10 +40,12 @@ IMAGE_LIB=gd # -------------------------------------------- # OPTIONAL: AWS S3 SETTINGS # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null +AWS_SECRET_ACCESS_KEY=null +AWS_ACCESS_KEY_ID=null +AWS_DEFAULT_REGION=null AWS_BUCKET=null +AWS_BUCKET_ROOT=null +AWS_URL=null # -------------------------------------------- diff --git a/.gitattributes b/.gitattributes index 2125666142..5ad9d096e2 100755 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ -* text=auto \ No newline at end of file +* text=auto +public/js/** binary +public/css/** binary diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml new file mode 100644 index 0000000000..8b294bb741 --- /dev/null +++ b/.github/autolabeler.yml @@ -0,0 +1,4 @@ +frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*"] +backend: ["/app", "*.php"] +legal: ["LICENSE*", "NOTICES*"] +config: .github diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000000..67a78c7c26 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,33 @@ +# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome + +# Comment to be posted to on first time issues +newIssueWelcomeComment: | + 👋 Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can. + +# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome + +# Comment to be posted to on PRs from first time contributors in your repository +newPRWelcomeComment: | + 💖 Thanks for this pull request! 💖 + + We use [semantic commit messages](https://snipe-it.readme.io/docs/contributing-overview#section-pull-request-guidelines) to streamline the release process and easily generate changelogs between versions. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix if it doesn't have one already. + + Examples of commit messages with semantic prefixes: + + - `Fixed #: don't overwrite prevent_default if default wasn't prevented` + - `Added #: add checkout functionality to assets` + - `Improved Asset Checkout: use new notification method for checkout` + + Things that will help get your PR across the finish line: + + - Document any user-facing changes you've made. + - Include tests when adding/changing behavior. + - Include screenshots and animated GIFs whenever possible. + + We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can. + +# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge + +# Comment to be posted to on pull requests merged by a first time user +firstPRMergeComment: > + Congrats on merging your first pull request! 🎉🎉🎉 diff --git a/.github/weekly-digest.yml b/.github/weekly-digest.yml new file mode 100644 index 0000000000..fe502fbc98 --- /dev/null +++ b/.github/weekly-digest.yml @@ -0,0 +1,7 @@ +# Configuration for weekly-digest - https://github.com/apps/weekly-digest +publishDay: sun +canPublishIssues: true +canPublishPullRequests: true +canPublishContributors: true +canPublishStargazers: true +canPublishCommits: true diff --git a/.gitignore b/.gitignore index 5012c49a8f..8af4d69762 100755 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,13 @@ tests/_support/_generated/* /storage/oauth-public.key *.cache + +.vagrant + +\.php_cs\.dist + +phpmd\.xml /public/storage +_ide_helper.php +.phpstorm.meta.php +_ide_helper_models.php diff --git a/.nvmrc b/.nvmrc index 0e26dd902c..70324da038 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v6.11.3 +v10.15.1 diff --git a/.travis.yml b/.travis.yml index 09e4581008..6ea67cb9d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,10 @@ services: # list any PHP version you want to test against php: - - 7.1.2 - 7.2 - - 7.3 + - 7.3.0 + - 7.4 -matrix: - allow_failures: - - php: 7.3 # execute any number of scripts before the test run, custom env's are available as variables before_script: @@ -31,6 +28,7 @@ before_script: - mysql -e 'CREATE USER "travis'@'localhost";' - mysql -e 'GRANT ALL PRIVILEGES ON * . * TO "travis'@'localhost";' - mysql -e 'FLUSH PRIVILEGES;' + - cp .env.testing-ci .env - composer self-update - composer install -n --prefer-source - chmod -R 777 storage diff --git a/Dockerfile b/Dockerfile index 0b8e8f72ac..35680b161c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,59 @@ -FROM ubuntu:xenial -LABEL maintainer="uberbrady, hinchk" +FROM ubuntu:bionic +LABEL maintainer Brady Wetherington -RUN apt-get update && apt-get install -y software-properties-common -RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php -RUN apt-get update && apt-get install -y \ +RUN export DEBIAN_FRONTEND=noninteractive; \ + export DEBCONF_NONINTERACTIVE_SEEN=true; \ + echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \ + echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \ + apt-get update -qqy \ + && apt-get install -qqy --no-install-recommends \ +apt-utils \ apache2 \ apache2-bin \ -libapache2-mod-php7.1 \ -php7.1-curl \ -php7.1-ldap \ -php7.1-mysql \ -php7.1-mcrypt \ -php7.1-gd \ -php7.1-xml \ -php7.1-mbstring \ -php7.1-zip \ -php7.1-bcmath \ +libapache2-mod-php7.2 \ +php7.2-curl \ +php7.2-ldap \ +php7.2-mysql \ +php7.2-gd \ +php7.2-xml \ +php7.2-mbstring \ +php7.2-zip \ +php7.2-bcmath \ patch \ curl \ +wget \ vim \ git \ +cron \ mysql-client \ supervisor \ +cron \ +gcc \ +make \ +autoconf \ +libc-dev \ +pkg-config \ +libmcrypt-dev \ +php7.2-dev \ +ca-certificates \ +unzip \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN curl -L -O https://github.com/pear/pearweb_phars/raw/master/go-pear.phar +RUN php go-pear.phar + +RUN pecl install mcrypt-1.0.2 + +RUN bash -c "echo extension=/usr/lib/php/20170718/mcrypt.so > /etc/php/7.2/mods-available/mcrypt.ini" + RUN phpenmod mcrypt RUN phpenmod gd RUN phpenmod bcmath -RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.1/apache2/php.ini -RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.1/cli/php.ini +RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.2/apache2/php.ini +RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.2/cli/php.ini RUN useradd -m --uid 1000 --gid 50 docker @@ -41,11 +64,11 @@ COPY docker/000-default.conf /etc/apache2/sites-enabled/000-default.conf #SSL RUN mkdir -p /var/lib/snipeit/ssl -COPY docker/001-default-ssl.conf /etc/apache2/sites-enabled/001-default-ssl.conf -#COPY docker/001-default-ssl.conf /etc/apache2/sites-available/001-default-ssl.conf +#COPY docker/001-default-ssl.conf /etc/apache2/sites-enabled/001-default-ssl.conf +COPY docker/001-default-ssl.conf /etc/apache2/sites-available/001-default-ssl.conf RUN a2enmod ssl -#RUN a2ensite 001-default-ssl.conf +RUN a2ensite 001-default-ssl.conf COPY . /var/www/html @@ -68,7 +91,7 @@ RUN \ rm -r "/var/www/html/storage/private_uploads" && ln -fs "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads" \ && rm -rf "/var/www/html/public/uploads" && ln -fs "/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads" \ && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \ - && mkdir "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ + && mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ && ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \ && chown docker "/var/lib/snipeit/keys/" \ && chmod +x /var/www/html/artisan \ @@ -77,11 +100,11 @@ RUN \ ############## DEPENDENCIES via COMPOSER ################### #global install of composer -RUN cd /tmp;curl -sS https://getcomposer.org/installer | php;mv /tmp/composer.phar /usr/local/bin/composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Get dependencies USER docker -RUN cd /var/www/html;composer install && rm -rf /home/docker/.composer/cache +RUN composer install --no-dev --working-dir=/var/www/html USER root ############### APPLICATION INSTALL/INIT ################# diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000000..f00650daf6 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,80 @@ +FROM alpine:3.8 +# Apache + PHP +RUN apk add --update --no-cache \ + apache2 \ + php7 \ + php7-common \ + php7-apache2 \ + php7-curl \ + php7-ldap \ + php7-mysqli \ + php7-gd \ + php7-xml \ + php7-mbstring \ + php7-zip \ + php7-ctype \ + php7-tokenizer \ + php7-pdo_mysql \ + php7-openssl \ + php7-bcmath \ + php7-phar \ + php7-json \ + php7-iconv \ + php7-fileinfo \ + php7-simplexml \ + php7-session \ + curl \ + wget \ + vim \ + git \ + mysql-client \ + tini + +# Where apache's PID lives +RUN mkdir -p /run/apache2 && chown apache:apache /run/apache2 + +RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php7/php.ini +COPY docker/000-default-2.4.conf /etc/apache2/conf.d/default.conf + +# Enable mod_rewrite +RUN sed -i '/LoadModule rewrite_module/s/^#//g' /etc/apache2/httpd.conf + +COPY . /var/www/html + +WORKDIR /var/www/html + +COPY docker/docker.env /var/www/html/.env + +RUN chown -R apache:apache /var/www/html + +RUN \ + rm -r "/var/www/html/storage/private_uploads" \ + && mkdir -p "/var/lib/snipeit/data/private_uploads" && ln -fs "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads" \ + && rm -rf "/var/www/html/public/uploads" \ + && mkdir -p "/var/lib/snipeit/data/uploads" && ln -fs "/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads" \ + && mkdir -p "/var/lib/snipeit/dumps" && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \ + && mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ + && ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \ + && chown -R apache "/var/lib/snipeit" + +# Install composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer +RUN mkdir -p /var/www/.composer && chown apache /var/www/.composer + +# Install dependencies +USER apache +RUN COMPOSER_CACHE_DIR=/dev/null composer install --no-dev --working-dir=/var/www/html + +USER root + +VOLUME ["/var/lib/snipeit"] + +# Entrypoints +COPY docker/entrypoint_alpine.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/sbin/tini", "--"] + +CMD ["/entrypoint.sh"] + +EXPOSE 80 diff --git a/README.md b/README.md index 20a6e35946..2e85a4ed60 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![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) [![All Contributors](https://img.shields.io/badge/all_contributors-189-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) +[![All Contributors](https://img.shields.io/badge/all_contributors-212-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) ## Snipe-IT - Open Source Asset Management System @@ -68,6 +69,15 @@ As these were created by third-parties, Snipe-IT cannot provide support for thes ----- +### Contributing + +Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview). + + +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + +----- + ### Security To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker. @@ -107,15 +117,13 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
ragnarcx](https://github.com/ragnarcx)
[🌍](#translation-ragnarcx "Translation") | [
Rein van Haaren](http://www.reinvanhaaren.nl/)
[🌍](#translation-reinvanhaaren "Translation") | [
Teguh Dwicaksana](http://dheche.songolimo.net)
[🌍](#translation-dheche "Translation") | [
fraccie](https://github.com/FRaccie)
[🌍](#translation-FRaccie "Translation") | [
vinzruzell](https://github.com/vinzruzell)
[🌍](#translation-vinzruzell "Translation") | [
Kevin Austin](http://kevinaustin.com)
[🌍](#translation-vipsystem "Translation") | [
Wira Sandy](http://azuraweb.xyz)
[🌍](#translation-wira-sandy "Translation") | | [
Илья](https://github.com/GrayHoax)
[🌍](#translation-GrayHoax "Translation") | [
GodUseVPN](https://github.com/godusevpn)
[🌍](#translation-godusevpn "Translation") | [
周周](https://github.com/EngrZhou)
[🌍](#translation-EngrZhou "Translation") | [
Sam](https://github.com/takuy)
[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [
Azerothian](https://www.illisian.com.au)
[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [
Tim Farmer](https://github.com/timothyfarmer)
[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [
Marián Skrip](https://github.com/mskrip)
[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") | | [
Godfrey Martinez](https://github.com/Godmartinz)
[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") | [
bigtreeEdo](https://github.com/bigtreeEdo)
[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [
Colin McNeil](https://colinmcneil.me/)
[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [
JoKneeMo](https://github.com/JoKneeMo)
[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [
Joshi](http://www.redbridge.se)
[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [
Anthony Burns](https://github.com/anthonypburns)
[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [
Alexander Chibrikin](http://phpprofi.ru/)
[💻](https://github.com/snipe/snipe-it/commits?author=alek13 "Code") | +| [
Илья](https://github.com/GrayHoax)
[🌍](#translation-GrayHoax "Translation") | [
GodUseVPN](https://github.com/godusevpn)
[🌍](#translation-godusevpn "Translation") | [
周周](https://github.com/EngrZhou)
[🌍](#translation-EngrZhou "Translation") | [
Sam](https://github.com/takuy)
[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [
Azerothian](https://www.illisian.com.au)
[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [
Wes Hulette](http://macfoo.wordpress.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=jwhulette "Code") | [
patrict](https://github.com/patrict)
[💻](https://github.com/snipe/snipe-it/commits?author=patrict "Code") | +| [
Dmitriy Minaev](https://github.com/VELIKII-DIVAN)
[💻](https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN "Code") | [
liquidhorse](https://github.com/liquidhorse)
[💻](https://github.com/snipe/snipe-it/commits?author=liquidhorse "Code") | [
Jordi Boggiano](https://seld.be/)
[💻](https://github.com/snipe/snipe-it/commits?author=Seldaek "Code") | [
Ivan Nieto](https://github.com/inietov)
[💻](https://github.com/snipe/snipe-it/commits?author=inietov "Code") | [
Ben RUBSON](https://github.com/benrubson)
[💻](https://github.com/snipe/snipe-it/commits?author=benrubson "Code") | [
NMathar](https://github.com/NMathar)
[💻](https://github.com/snipe/snipe-it/commits?author=NMathar "Code") | [
Steffen](https://github.com/smb)
[💻](https://github.com/snipe/snipe-it/commits?author=smb "Code") | +| [
Sxderp](https://github.com/Sxderp)
[💻](https://github.com/snipe/snipe-it/commits?author=Sxderp "Code") | [
fanta8897](https://github.com/fanta8897)
[💻](https://github.com/snipe/snipe-it/commits?author=fanta8897 "Code") | [
Andrey Bolonin](https://andreybolonin.com/phpconsulting/)
[💻](https://github.com/snipe/snipe-it/commits?author=andreybolonin "Code") | [
shinayoshi](http://www.shinayoshi.net/)
[💻](https://github.com/snipe/snipe-it/commits?author=shinayoshi "Code") | [
Hubert](https://github.com/reuser)
[💻](https://github.com/snipe/snipe-it/commits?author=reuser "Code") | [
KeenRivals](https://brashear.me)
[💻](https://github.com/snipe/snipe-it/commits?author=KeenRivals "Code") | [
omyno](https://github.com/omyno)
[💻](https://github.com/snipe/snipe-it/commits?author=omyno "Code") | +| [
Evgeny](https://github.com/jackka)
[💻](https://github.com/snipe/snipe-it/commits?author=jackka "Code") | [
Colin Campbell](https://digitalist.se)
[💻](https://github.com/snipe/snipe-it/commits?author=colin-campbell "Code") | [
Ľubomír Kučera](https://github.com/lubo)
[💻](https://github.com/snipe/snipe-it/commits?author=lubo "Code") | [
Martin Meredith](https://www.sourceguru.net)
[💻](https://github.com/snipe/snipe-it/commits?author=Mezzle "Code") | [
Tim Farmer](https://github.com/timothyfarmer)
[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [
Marián Skrip](https://github.com/mskrip)
[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") | [
Godfrey Martinez](https://github.com/Godmartinz)
[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") | +| [
bigtreeEdo](https://github.com/bigtreeEdo)
[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [
Colin McNeil](https://colinmcneil.me/)
[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [
JoKneeMo](https://github.com/JoKneeMo)
[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [
Joshi](http://www.redbridge.se)
[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [
Anthony Burns](https://github.com/anthonypburns)
[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [
johnson-yi](https://github.com/johnson-yi)
[💻](https://github.com/snipe/snipe-it/commits?author=johnson-yi "Code") | [
Sanjay Govind](https://tangentmc.net)
[💻](https://github.com/snipe/snipe-it/commits?author=sanjay900 "Code") | +| [
Peter Upfold](https://peter.upfold.org.uk/)
[💻](https://github.com/snipe/snipe-it/commits?author=PeterUpfold "Code") | [
Jared Biel](https://github.com/jbiel)
[💻](https://github.com/snipe/snipe-it/commits?author=jbiel "Code") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! ------ - -### Contributing - -Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview). - - -Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. diff --git a/Vagrantfile b/Vagrantfile index b65979b7e9..0c5f8798a6 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -81,4 +81,22 @@ Vagrant.configure("2") do |config| fedora26.vm.provision :shell, :inline => "wget #{SNIPEIT_SH_URL}" fedora26.vm.provision :shell, :inline => "chmod 755 snipeit.sh" end + + config.vm.define "freebsd" do |freebsd| + freebsd.vm.box = "freebsd/FreeBSD-11.2-RELEASE" + freebsd.vm.hostname = 'freebsd12' + freebsd.vm.network "forwarded_port", guest: 80, host: 8080 + freebsd.vm.network "forwarded_port", guest:3306, host:3306 # mysql + freebsd.vm.network "private_network", type: "dhcp" + freebsd.ssh.shell = "sh" + freebsd.vm.base_mac = "080027D14C66" + freebsd.vm.synced_folder ".", "/vagrant", :nfs => true, id: "vagrant-root", + :mount_options => ['rw', 'vers=3', 'tcp', 'actimeo=2'] + freebsd.vm.provision "shell", inline: <<-SHELL + pkg install -y python27; + SHELL + freebsd.vm.provision "ansible" do |ansible| + ansible.playbook = "ansible/freebsd/vagrant_playbook.yml" + end + end end diff --git a/ansible/freebsd/vagrant_playbook.yml b/ansible/freebsd/vagrant_playbook.yml new file mode 100644 index 0000000000..7e10ca0d86 --- /dev/null +++ b/ansible/freebsd/vagrant_playbook.yml @@ -0,0 +1,260 @@ +--- +- name: Set up local server + hosts: all + remote_user: vagrant + become_user: root + become_method: sudo + vars: + - ansible_python_interpreter: /usr/local/bin/python2.7 + gather_facts: no + +# Tasks + tasks: + + # + # Update the PKG database + # + - name: Upgrade PKG database + raw: sudo pkg upgrade -y + + # + # Mount the shared folders + # + - name: Update Vagrant Shared Folders + command: "{{ item }}" + with_items: + - sysrc rpc_lockd_enable=YES + - sysrc rpc_statd_enable=YES + become: true + + # + # Install required utilities + # + - name: Install Utilities + pkgng: + name: "{{ item }}" + state: present + with_items: + - openssl + - node + - npm + - git + - nano + - wget + - bash + become: true + + # + # Install php and php dependancies + # + - name: Install PHP dependancies + pkgng: + name: "{{ item }}" + state: present + with_items: + - php72 + - php72-zip + - php72-zlib + - php72-extensions + - php72-mbstring + - php72-openssl + # - php72-mysqli + - php72-curl + - php72-soap + - php72-pdo_mysql + # - php72-pdo_pgsql + - php72-ldap + - php72-curl + - php72-fileinfo + - php72-bcmath + - php72-gd + become: true + + # + # Create a php.ini file + # + - name: PHP INI check + stat: + path: /usr/local/etc/php.ini + register: php_ini_exits + + - name: Create PHP ini + command: cp /usr/local/etc/php.ini-development /usr/local/etc/php.ini + become: true + when: not php_ini_exits.stat.exists + + - name: Enable PHP-FPM auto-start + command: sysrc php_fpm_enable=YES + become: true + + - name: Start PHP-FPM service + service: + name: php-fpm + state: started + become: true + + # + # Install the lastest version of composer + # + - name: Composer check + stat: + path: /usr/local/bin/composer + register: composer_exits + + - name: Install Composer + shell: | + EXPECTED_SIGNATURE=$(wget -q -O - https://composer.github.io/installer.sig) + php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" + ACTUAL_SIGNATURE=$(php -r "echo hash_file('SHA384', 'composer-setup.php');") + + if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ] + then + >&2 echo 'ERROR: Invalid installer signature' + rm composer-setup.php + exit 1 + fi + + php composer-setup.php --quiet + RESULT=$? + rm composer-setup.php + mv composer.phar /usr/local/bin/composer + exit $RESULT + when: not composer_exits.stat.exists + become: true + + # + # Install MySQL Server + + - name: Install MySQL 5.7 + pkgng: + name: mysql57-server + state: present + become: true + register: sql_server + + - name: Start MySQL server + service: + name: mysql-server + state: started + become: true + + - name: MySQL 5.7 auto-start + command: sysrc mysql_enable=YES + become: true + when: sql_server.changed == true + + - name: Get MySQL root password + command: tail -1 /root/.mysql_secret + register: myql_root_pwd + become: true + when: sql_server.changed == true + + - name: Change MySQL root password + command: mysqladmin -u root -p'{{myql_root_pwd.stdout}}' password vagrant + when: sql_server.changed == true + + - name: Enable remote mysql + replace: + path: /usr/local/etc/mysql/my.cnf + regexp: "127.0.0.1" + replace: "0.0.0.0" + become: true + when: sql_server.changed == true + + - name: Grant user vagrant privelages + shell: mysql -u root -pvagrant -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'vagrant' WITH GRANT OPTION; FLUSH PRIVILEGES;" + become: true + when: sql_server.changed == true + ignore_errors: true + + - name: Restart MySQL server + service: + name: mysql-server + state: restarted + become: true + + + # + # Install Apache Web Server + # + - name: Install Apache 2.4 + pkgng: + name: apache24 + state: present + become: true + register: apache24_server + + - name: Apache 2.4 auto-start + command: sysrc apache24_enable=YES + become: true + when: apache24_server.changed == true + + - name: Enable Apache modules + replace: + path: /usr/local/etc/apache24/httpd.conf + regexp: "#{{ item }}" + replace: "{{ item }}" + become: true + with_items: + - LoadModule rewrite_module libexec/apache24/mod_rewrite.so + - LoadModule vhost_alias_module libexec/apache24/mod_vhost_alias.so + - LoadModule deflate_module libexec/apache24/mod_deflate.so + - LoadModule expires_module libexec/apache24/mod_expires.so + - LoadModule mpm_worker_module libexec/apache24/mod_mpm_worker.so + - LoadModule proxy_fcgi_module libexec/apache24/mod_proxy_fcgi.so + - LoadModule proxy_module libexec/apache24/mod_proxy.so + - Include etc/apache24/extra/httpd-vhosts.conf + when: apache24_server.changed == true + + - name: Disable Apache modules + replace: + path: /usr/local/etc/apache24/httpd.conf + regexp: "{{ item }}" + replace: "#{{ item }}" + become: true + with_items: + - LoadModule mpm_prefork_module libexec/apache24/mod_mpm_prefork.so + when: apache24_server.changed == true + + - name: Backup vhosts + command: cp /usr/local/etc/apache24/extra/httpd-vhosts.conf /usr/local/etc/apache24/extra/httpd-vhosts.conf.bak + become: true + when: apache24_server.changed == true + + - name: Truncate vhosts + command: truncate -s 0 /usr/local/etc/apache24/extra/httpd-vhosts.conf + become: true + when: apache24_server.changed == true + + - name: Set up vhost + blockinfile: + path: "/usr/local/etc/apache24/extra/httpd-vhosts.conf" + block: | + + DocumentRoot /usr/local/www/apache24/data/public + ServerName vagrant.app + ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/local/www/apache24/data/public/$1 + DirectoryIndex /index.php index.php + + Options -Indexes +FollowSymLinks + AllowOverride All + Require all granted + + + become: true + when: apache24_server.changed == true + + - name: Map apache dir to local folder + shell: | + if ! [ -L /var/www ]; then + rm -rf /usr/local/www/apache24/data; + ln -fs /vagrant /usr/local/www/apache24/data; + fi + become: true + when: apache24_server.changed == true + + - name: Start Apache 2.4 server + service: + name: apache24 + state: started + become: true \ No newline at end of file diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php index 89b564091e..7a2c9a1feb 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdmin.php @@ -76,10 +76,4 @@ class CreateAdmin extends Command } - // protected function getArguments() - // { - // return array( - // array('username', InputArgument::REQUIRED, 'Username'), - // ); - // } } diff --git a/app/Console/Commands/DisableLDAP.php b/app/Console/Commands/DisableLDAP.php index 8e9d8c8d69..fd2f0a1070 100644 --- a/app/Console/Commands/DisableLDAP.php +++ b/app/Console/Commands/DisableLDAP.php @@ -2,8 +2,8 @@ namespace App\Console\Commands; -use Illuminate\Console\Command; use App\Models\Setting; +use Illuminate\Console\Command; class DisableLDAP extends Command { @@ -41,7 +41,7 @@ class DisableLDAP extends Command if ($this->confirm("\n****************************************************\nThis will disable LDAP support. You will not be able \nto login with an account that does not exist \nlocally in the Snipe-IT local database. \n****************************************************\n\nDo you wish to continue? [y|N]")) { - $setting = Setting::first(); + $setting = Setting::getSettings(); $setting->ldap_enabled = 0; if ($setting->save()) { $this->info('LDAP has been set to disabled.'); diff --git a/app/Console/Commands/FixDoubleEscape.php b/app/Console/Commands/FixDoubleEscape.php index 648e209950..64f6aad572 100644 --- a/app/Console/Commands/FixDoubleEscape.php +++ b/app/Console/Commands/FixDoubleEscape.php @@ -71,7 +71,7 @@ class FixDoubleEscape extends Command foreach($classname::where("$field",'LIKE','%&%')->get() as $row) { $this->info('Updating '.$field.' for '.$classname); - $row->{$field} = html_entity_decode($row->{$field}); + $row->{$field} = html_entity_decode($row->{$field},ENT_QUOTES); $row->save(); $count[$classname][$field]++; diff --git a/app/Console/Commands/ImportLocations.php b/app/Console/Commands/ImportLocations.php index b037b011bf..f36a384c1f 100644 --- a/app/Console/Commands/ImportLocations.php +++ b/app/Console/Commands/ImportLocations.php @@ -120,7 +120,7 @@ class ImportLocations extends Command if (array_key_exists('Country', $row)) { $location->country = trim($row['Country']); } - if (array_key_exists('Country', $row)) { + if (array_key_exists('OU', $row)) { $location->ldap_ou = trim($row['OU']); } diff --git a/app/Console/Commands/LdapSync.php b/app/Console/Commands/LdapSync.php old mode 100755 new mode 100644 index aba23151aa..9b0365f630 --- a/app/Console/Commands/LdapSync.php +++ b/app/Console/Commands/LdapSync.php @@ -1,14 +1,24 @@ + * + * @since 5.0.0 + */ class LdapSync extends Command { /** @@ -16,23 +26,79 @@ class LdapSync extends Command * * @var string */ - protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--summary} {--json_summary}'; + protected $signature = 'snipeit:ldap-sync + {--location= : A location name } + {--location_id= : A location id} + {--base_dn= : A diffrent base DN to use } + {--summary : Print summary } + {--json_summary : Print summary in json format } + {--dryrun : Run the sync process but don\'t update the database}'; /** * The console command description. * * @var string */ - protected $description = 'Command line LDAP sync'; + protected $description = 'Command line LDAP/AD sync'; + + /** + * An LdapAd instance. + * + * @var \App\Models\LdapAd + */ + private $ldap; + + /** + * LDAP settings collection. + * + * @var \Illuminate\Support\Collection + */ + private $settings = null; + + /** + * A default location collection. + * + * @var \Illuminate\Support\Collection + */ + private $defaultLocation = null; + + /** + * Mapped locations collection. + * + * @var \Illuminate\Support\Collection + */ + private $mappedLocations = null; + + /** + * The summary collection. + * + * @var \Illuminate\Support\Collection + */ + private $summary; + + /** + * Is dry-run? + * + * @var bool + */ + private $dryrun = false; + + /** + * Show users to be imported. + * + * @var array + */ + private $userlist = []; /** * Create a new command instance. - * - * @return void */ - public function __construct() + public function __construct(LdapAd $ldap) { parent::__construct(); + $this->ldap = $ldap; + $this->settings = $this->ldap->ldapSettings; + $this->summary = collect(); } /** @@ -42,241 +108,274 @@ class LdapSync extends Command */ public function handle() { - ini_set('max_execution_time', env('LDAP_TIME_LIM', 600)); //600 seconds = 10 minutes - ini_set('memory_limit', env('LDAP_MEM_LIM', '500M')); - $ldap_result_username = Setting::getSettings()->ldap_username_field; - $ldap_result_last_name = Setting::getSettings()->ldap_lname_field; - $ldap_result_first_name = Setting::getSettings()->ldap_fname_field; + ini_set('max_execution_time', '600'); //600 seconds = 10 minutes + ini_set('memory_limit', '500M'); + $old_error_reporting = error_reporting(); // grab old error_reporting .ini setting, for later re-enablement + error_reporting($old_error_reporting & ~E_DEPRECATED); // disable deprecation warnings, for LDAP in PHP 7.4 (and greater) - $ldap_result_active_flag = Setting::getSettings()->ldap_active_flag_field; - $ldap_result_emp_num = Setting::getSettings()->ldap_emp_num; - $ldap_result_email = Setting::getSettings()->ldap_email; - - try { - $ldapconn = Ldap::connectToLdap(); - Ldap::bindAdminToLdap($ldapconn); - } catch (\Exception $e) { - if ($this->option('json_summary')) { - $json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ]; - $this->info(json_encode($json_summary)); - } - LOG::info($e); - return []; + if ($this->option('dryrun')) { + $this->dryrun = true; + } + $this->checkIfLdapIsEnabled(); + $this->checkLdapConnetion(); + $this->setBaseDn(); + $this->getUserDefaultLocation(); + /* + * Use the default location if set, this is needed for the LDAP users sync page + */ + if (!$this->option('base_dn') && null == $this->defaultLocation) { + $this->getMappedLocations(); + } + $this->processLdapUsers(); + // Print table of users + if ($this->dryrun) { + $this->info('The following users will be synced!'); + $headers = ['First Name', 'Last Name', 'Username', 'Email', 'Employee #', 'Location Id', 'Status']; + $this->table($headers, $this->summary->toArray()); } - $summary = array(); + error_reporting($old_error_reporting); // re-enable deprecation warnings. + return $this->getSummary(); + } - try { - if ($this->option('base_dn') != '') { - $search_base = $this->option('base_dn'); - LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".'); - } else { - $search_base = null; - } - $results = Ldap::findLdapUsers($search_base); - } catch (\Exception $e) { - if ($this->option('json_summary')) { - $json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ]; - $this->info(json_encode($json_summary)); - } - LOG::info($e); - return []; - } + /** + * Generate the LDAP sync summary. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return string + */ + private function getSummary(): string + { + if ($this->option('summary') && null === $this->dryrun) { + $this->summary->each(function ($item) { + $this->info('USER: '.$item['note']); - /* Determine which location to assign users to by default. */ - $location = NULL; - - if ($this->option('location')!='') { - $location = Location::where('name', '=', $this->option('location'))->first(); - LOG::debug('Location name '.$this->option('location').' passed'); - LOG::debug('Importing to '.$location->name.' ('.$location->id.')'); - } elseif ($this->option('location_id')!='') { - $location = Location::where('id', '=', $this->option('location_id'))->first(); - LOG::debug('Location ID '.$this->option('location_id').' passed'); - LOG::debug('Importing to '.$location->name.' ('.$location->id.')'); - } - - if (!isset($location)) { - LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.'); - } - - /* Process locations with explicitly defined OUs, if doing a full import. */ - if ($this->option('base_dn')=='') { - // Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993) - $ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray(); - $ldap_ou_lengths = array(); - - foreach ($ldap_ou_locations as $location) { - $ldap_ou_lengths[] = strlen($location["ldap_ou"]); - } - - array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations); - - if (sizeof($ldap_ou_locations) > 0) { - LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.'); - } - - // Inject location information fields - for ($i = 0; $i < $results["count"]; $i++) { - $results[$i]["ldap_location_override"] = false; - $results[$i]["location_id"] = 0; - } - - // Grab subsets based on location-specific DNs, and overwrite location for these users. - foreach ($ldap_ou_locations as $ldap_loc) { - try { - $location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]); - } catch (\Exception $e) { // FIXME: this is stolen from line 77 or so above - if ($this->option('json_summary')) { - $json_summary = [ "error" => true, "error_message" => trans('admin/users/message.error.ldap_could_not_search')." Location: ".$ldap_loc['name']." (ID: ".$ldap_loc['id'].") cannot connect to \"".$ldap_loc["ldap_ou"]."\" - ".$e->getMessage(), "summary" => [] ]; - $this->info(json_encode($json_summary)); - } - LOG::info($e); - return []; + if ('ERROR' === $item['status']) { + $this->error('ERROR: '.$item['note']); } - $usernames = array(); - for ($i = 0; $i < $location_users["count"]; $i++) { - - if (array_key_exists($ldap_result_username, $location_users[$i])) { - $location_users[$i]["ldap_location_override"] = true; - $location_users[$i]["location_id"] = $ldap_loc["id"]; - $usernames[] = $location_users[$i][$ldap_result_username][0]; - } - - } - - // Delete located users from the general group. - foreach ($results as $key => $generic_entry) { - if ((is_array($generic_entry)) && (array_key_exists($ldap_result_username, $generic_entry))) { - if (in_array($generic_entry[$ldap_result_username][0], $usernames)) { - unset($results[$key]); - } - } - } - - $global_count = $results['count']; - $results = array_merge($location_users, $results); - $results['count'] = $global_count; - } - } - - /* Create user account entries in Snipe-IT */ - $tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20); - $pass = bcrypt($tmp_pass); - - for ($i = 0; $i < $results["count"]; $i++) { - if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == "TRUE") { - - $item = array(); - $item["username"] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : ""; - $item["employee_number"] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : ""; - $item["lastname"] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : ""; - $item["firstname"] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : ""; - $item["email"] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : "" ; - $item["ldap_location_override"] = isset($results[$i]["ldap_location_override"]) ? $results[$i]["ldap_location_override"]:""; - $item["location_id"] = isset($results[$i]["location_id"]) ? $results[$i]["location_id"]:""; - - $user = User::where('username', $item["username"])->first(); - if ($user) { - // Updating an existing user. - $item["createorupdate"] = 'updated'; - } else { - // Creating a new user. - $user = new User; - $user->password = $pass; - $user->activated = 0; - $item["createorupdate"] = 'created'; - } - - $user->first_name = $item["firstname"]; - $user->last_name = $item["lastname"]; - $user->username = $item["username"]; - $user->email = $item["email"]; - $user->employee_num = e($item["employee_number"]); - - // Sync activated state for Active Directory. - if ( array_key_exists('useraccountcontrol', $results[$i]) ) { - /* The following is _probably_ the correct logic, but we can't use it because - some users may have been dependent upon the previous behavior, and this - could cause additional access to be available to users they don't want - to allow to log in. - - $useraccountcontrol = $results[$i]['useraccountcontrol'][0]; - if( - // based on MS docs at: https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties - ($useraccountcontrol & 0x200) && // is a NORMAL_ACCOUNT - !($useraccountcontrol & 0x02) && // *and* _not_ ACCOUNTDISABLE - !($useraccountcontrol & 0x10) // *and* _not_ LOCKOUT - ) { - $user->activated = 1; - } else { - $user->activated = 0; - } */ - $enabled_accounts = [ - '512', // 0x200 NORMAL_ACCOUNT - '544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD - '66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD - '66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD - '262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED - '262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED - '328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD - '328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD - '4260352',// 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH - '1049088',// 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED - ]; - $user->activated = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0; - } - - // If we're not using AD, and there isn't an activated flag set, activate all users - elseif (empty($ldap_result_active_flag)) { - $user->activated = 1; - } - - if ($item['ldap_location_override'] == true) { - $user->location_id = $item['location_id']; - } elseif ((isset($location)) && (!empty($location))) { - - if ((is_array($location)) && (array_key_exists('id', $location))) { - $user->location_id = $location['id']; - } elseif (is_object($location)) { - $user->location_id = $location->id; - } - - } - - $user->ldap_import = 1; - - $errors = ''; - - if ($user->save()) { - $item["note"] = $item["createorupdate"]; - $item["status"]='success'; - } else { - foreach ($user->getErrors()->getMessages() as $key => $err) { - $errors .= $err[0]; - } - $item["note"] = $errors; - $item["status"]='error'; - } - - array_push($summary, $item); - } - - } - - if ($this->option('summary')) { - for ($x = 0; $x < count($summary); $x++) { - if ($summary[$x]['status']=='error') { - $this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was not imported: '.$summary[$x]['note']); - } else { - $this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was '.strtoupper($summary[$x]['createorupdate']).'.'); - } - } - } else if ($this->option('json_summary')) { - $json_summary = [ "error" => false, "error_message" => "", "summary" => $summary ]; // hardcoding the error to false and the error_message to blank seems a bit weird + }); + } elseif ($this->option('json_summary')) { + $json_summary = [ + 'error' => false, + 'error_message' => '', + 'summary' => $this->summary->toArray(), + ]; $this->info(json_encode($json_summary)); - } else { - return $summary; + } + + return ''; + } + + /** + * Create a new user or update an existing user. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $snipeUser + */ + private function updateCreateUser(AdldapUser $snipeUser): void + { + $user = $this->ldap->processUser($snipeUser, $this->defaultLocation, $this->mappedLocations); + $summary = [ + 'firstname' => $user->first_name, + 'lastname' => $user->last_name, + 'username' => $user->username, + 'employee_number' => $user->employee_num, + 'email' => $user->email, + 'location_id' => $user->location_id, + ]; + // Only update the database if is not a dry run + if (!$this->dryrun) { + if ($user->save()) { + $summary['note'] = ($user->wasRecentlyCreated ? 'CREATED' : 'UPDATED'); + $summary['status'] = 'SUCCESS'; + } else { + $errors = ''; + foreach ($user->getErrors()->getMessages() as $error) { + $errors .= $error[0]; + } + $summary['note'] = $userMsg.' was not imported. REASON: '.$errors; + $summary['status'] = 'ERROR'; + } + } + + $summary['note'] = ($user->getOriginal('username') ? 'UPDATED' : 'CREATED'); + $this->summary->push($summary); + } + + /** + * Process the users to update / create. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param int $page The page to get the result set + */ + private function processLdapUsers(int $page=0): void + { + try { + $ldapUsers = $this->ldap->getLdapUsers($page); + } catch (Exception $e) { + $this->outputError($e); + exit($e->getMessage()); + } + + if (0 == $ldapUsers->count()) { + $msg = 'ERROR: No users found!'; + Log::error($msg); + if ($this->dryrun) { + $this->error($msg); + } + exit($msg); + } + + // Process each individual users + foreach ($ldapUsers as $user) { + $this->updateCreateUser($user); + } + + if ($ldapUsers->getCurrentPage() < $ldapUsers->getPages()-1) { + $this->processLdapUsers($ldapUsers->getCurrentPage() + 1); } } + + /** + * Get the mapped locations if a base_dn is provided. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function getMappedLocations() + { + $ldapOuLocation = Location::where('ldap_ou', '!=', '')->select(['id', 'ldap_ou'])->get(); + $locations = $ldapOuLocation->sortBy(function ($ou, $key) { + return strlen($ou->ldap_ou); + }); + if ($locations->count() > 0) { + $msg = 'Some locations have special OUs set. Locations will be automatically set for users in those OUs.'; + LOG::debug($msg); + if ($this->dryrun) { + $this->info($msg); + } + + $this->mappedLocations = $locations->pluck('ldap_ou', 'id'); + } + } + + /** + * Set the base dn if supplied. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function setBaseDn(): void + { + if ($this->option('base_dn')) { + $this->ldap->baseDn = $this->option('base_dn'); + $msg = sprintf('Importing users from specified base DN: "%s"', $this->ldap->baseDn); + LOG::debug($msg); + if ($this->dryrun) { + $this->info($msg); + } + } + } + + /** + * Get a default location id for imported users. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function getUserDefaultLocation(): void + { + $location = $this->option('location_id') ?? $this->option('location'); + if ($location) { + $userLocation = Location::where('name', '=', $location) + ->orWhere('id', '=', intval($location)) + ->select(['name', 'id']) + ->first(); + if ($userLocation) { + $msg = 'Importing users with default location: '.$userLocation->name.' ('.$userLocation->id.')'; + LOG::debug($msg); + + if ($this->dryrun) { + $this->info($msg); + } + + $this->defaultLocation = collect([ + $userLocation->id => $userLocation->name, + ]); + } else { + $msg = 'The supplied location is invalid!'; + LOG::error($msg); + if ($this->dryrun) { + $this->error($msg); + } + exit(0); + } + } + } + + /** + * Check if LDAP intergration is enabled. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function checkIfLdapIsEnabled(): void + { + if (false === $this->settings['ldap_enabled']) { + $msg = 'LDAP intergration is not enabled. Exiting sync process.'; + $this->info($msg); + Log::info($msg); + exit(0); + } + } + + /** + * Check to make sure we can access the server. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function checkLdapConnetion(): void + { + try { + $this->ldap->testLdapAdUserConnection(); + $this->ldap->testLdapAdBindConnection(); + } catch (Exception $e) { + $this->outputError($e); + exit(0); + } + } + + /** + * Output the json summary to the screen if enabled. + * + * @param Exception $error + */ + private function outputError($error): void + { + if ($this->option('json_summary')) { + $json_summary = [ + 'error' => true, + 'error_message' => $error->getMessage(), + 'summary' => [], + ]; + $this->info(json_encode($json_summary)); + } + $this->error($error->getMessage()); + LOG::error($error); + } } diff --git a/app/Console/Commands/MoveUploadsToNewDisk.php b/app/Console/Commands/MoveUploadsToNewDisk.php new file mode 100644 index 0000000000..6794a09f4d --- /dev/null +++ b/app/Console/Commands/MoveUploadsToNewDisk.php @@ -0,0 +1,183 @@ +error('Your current disk is set to local so we cannot proceed.'); + $this->warn("Please configure your .env settings for S3. \nChange your PUBLIC_FILESYSTEM_DISK value to 's3_public' and your PRIVATE_FILESYSTEM_DISK to s3_private."); + return false; + } + $delete_local = $this->argument('delete_local'); + + $public_uploads['accessories'] = glob('storage/app/public/accessories'."/*.*"); + $public_uploads['assets'] = glob('storage/app/public/assets'."/*.*"); + $public_uploads['avatars'] = glob('storage/app/public/avatars'."/*.*"); + $public_uploads['categories'] = glob('storage/app/public/categories'."/*.*"); + $public_uploads['companies'] = glob('storage/app/public/companies'."/*.*"); + $public_uploads['components'] = glob('storage/app/public/components'."/*.*"); + $public_uploads['consumables'] = glob('storage/app/public/consumables'."/*.*"); + $public_uploads['departments'] = glob('storage/app/public/departments'."/*.*"); + $public_uploads['locations'] = glob('storage/app/public/locations'."/*.*"); + $public_uploads['manufacturers'] = glob('storage/app/public/manufacturers'."/*.*"); + $public_uploads['suppliers'] = glob('storage/app/public/suppliers'."/*.*"); + $public_uploads['assetmodels'] = glob('storage/app/public/models'."/*.*"); + + + // iterate files + foreach($public_uploads as $public_type => $public_upload) + { + $type_count = 0; + $this->info("\nThere are ".count($public_upload).' PUBLIC '.$public_type.' files.'); + + for ($i = 0; $i < count($public_upload); $i++) { + $type_count++; + $filename = basename($public_upload[$i]); + + try { + Storage::disk('public')->put($public_type.'/'.$filename, file_get_contents($public_upload[$i])); + $new_url = Storage::disk('public')->url($public_type.'/'.$filename, $filename); + $this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url); + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + + } + + $logos = glob('public/uploads'."/setting*.*"); + $this->info("\nThere are ".count($logos).' files that might be logos.'); + $type_count = 0; + + for ($l = 0; $l < count($logos); $l++) { + $type_count++; + $filename = basename($logos[$l]); + $new_url = Storage::disk('public')->url($logos[$l], file_get_contents($public_upload[$i])); + $this->info($type_count.'. LOGO: '.$filename.' was copied to '.$new_url); + } + + $private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*"); + $private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*"); + $private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*"); + $private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*"); + $private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*"); + $private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*"); + $private_uploads['users'] = glob('storage/private_uploads/users'."/*.*"); + $private_uploads['backups'] = glob('storage/private_uploads/users'."/*.*"); + + + foreach($private_uploads as $private_type => $private_upload) + { + $this->info("\nThere are ".count($private_upload).' PRIVATE '.$private_type.' files.'); + // $this->info(print_r($private_upload, true)); + + $type_count = 0; + for ($x = 0; $x < count($private_upload); $x++) { + $type_count++; + $filename = basename($private_upload[$x]); + + try { + Storage::disk('private_uploads')->put($private_type.'/'.$filename, file_get_contents($public_upload[$i])); + $new_url = Storage::url($private_type.'/'.$filename, $filename); + $this->info($type_count.'. PRIVATE: '.$filename.' was copied to '.$new_url); + + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + + } + + + if ($delete_local=='true') { + $public_delete_count = 0; + $private_delete_count = 0; + + $this->info("\n\n"); + $this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); + $this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n"); + $this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); + + if ($this->confirm("Do you wish to continue?")) { + + foreach($public_uploads as $public_type => $public_upload) { + + for ($i = 0; $i < count($public_upload); $i++) { + $filename = $public_upload[$i]; + try { + unlink($filename); + $public_delete_count++; + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + } + + foreach($private_uploads as $private_type => $private_upload) + { + + for ($i = 0; $i < count($private_upload); $i++) { + $filename = $private_upload[$i]; + try { + unlink($filename); + $private_delete_count++; + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + } + + $this->info($public_delete_count." PUBLIC local files and ".$private_delete_count." PRIVATE local files were deleted from your filesystem."); + } + } + + + + + } +} diff --git a/app/Console/Commands/ObjectImportCommand.php b/app/Console/Commands/ObjectImportCommand.php index 9f09ea7184..83d88ffb27 100644 --- a/app/Console/Commands/ObjectImportCommand.php +++ b/app/Console/Commands/ObjectImportCommand.php @@ -1,31 +1,9 @@ whereNotNull('email')->with('assets', 'accessories', 'licenses')->get(); + + $count = 0; + foreach ($users as $user) { + + if (($user->assets->count() > 0) || ($user->accessories->count() > 0) || ($user->licenses->count() > 0)) + { + $count++; + $user->notify((new CurrentInventory($user))); + } + + } + + $this->info($count.' users notified.'); + + + } +} diff --git a/app/Console/Commands/SendExpectedCheckinAlerts.php b/app/Console/Commands/SendExpectedCheckinAlerts.php index dc01fba01d..d10791200d 100644 --- a/app/Console/Commands/SendExpectedCheckinAlerts.php +++ b/app/Console/Commands/SendExpectedCheckinAlerts.php @@ -2,17 +2,15 @@ namespace App\Console\Commands; - use App\Models\Asset; use App\Models\Setting; -use Illuminate\Console\Command; -use App\Notifications\ExpectedCheckinNotification; use App\Notifications\ExpectedCheckinAdminNotification; +use App\Notifications\ExpectedCheckinNotification; use Carbon\Carbon; +use Illuminate\Console\Command; class SendExpectedCheckinAlerts extends Command { - /** * The console command name. * @@ -29,8 +27,6 @@ class SendExpectedCheckinAlerts extends Command /** * Create a new command instance. - * - * @return void */ public function __construct() { @@ -44,15 +40,15 @@ class SendExpectedCheckinAlerts extends Command */ public function handle() { - $settings = Setting::getSettings(); + $settings = Setting::getSettings(); $whenNotify = Carbon::now()->addDays(7); - $assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get(); + $assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get(); - $this->info($whenNotify.' is deadline'); - $this->info($assets->count().' assets'); + $this->info($whenNotify . ' is deadline'); + $this->info($assets->count() . ' assets'); foreach ($assets as $asset) { - if ($asset->assigned && $asset->checkedOutToUser()) { + if ($asset->assigned && $asset->checkedOutToUser()) { $asset->assigned->notify((new ExpectedCheckinNotification($asset))); } } @@ -60,14 +56,9 @@ class SendExpectedCheckinAlerts extends Command if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) { // Send a rollup to the admin, if settings dictate $recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) { - return new \App\Models\Recipients\AlertRecipient($item); + return new AlertRecipient($item); }); - \Notification::send($recipients, new ExpectedCheckinAdminNotification($assets)); + Notification::send($recipients, new ExpectedCheckinAdminNotification($assets)); } - - - - - } } diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index 6fb331b18b..858f33b345 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -4,16 +4,14 @@ namespace App\Console\Commands; use App\Models\Asset; use App\Models\License; +use App\Models\Recipients\AlertRecipient; use App\Models\Setting; -use DB; -use App\Notifications\ExpiringLicenseNotification; use App\Notifications\ExpiringAssetsNotification; - +use App\Notifications\ExpiringLicenseNotification; use Illuminate\Console\Command; class SendExpirationAlerts extends Command { - /** * The console command name. * @@ -30,8 +28,6 @@ class SendExpirationAlerts extends Command /** * Create a new command instance. - * - * @return void */ public function __construct() { @@ -45,48 +41,35 @@ class SendExpirationAlerts extends Command */ public function handle() { - - $settings = Setting::getSettings(); + $settings = Setting::getSettings(); $threshold = $settings->alert_interval; - if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) { // Send a rollup to the admin, if settings dictate $recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) { - return new \App\Models\Recipients\AlertRecipient($item); + return new AlertRecipient($item); }); // Expiring Assets - $assets = Asset::getExpiringWarrantee(Setting::getSettings()->alert_interval); + $assets = Asset::getExpiringWarrantee($threshold); if ($assets->count() > 0) { - $this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), - ['count' => $assets->count(), 'threshold' => $threshold])); - \Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold)); + $this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold])); + Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold)); } // Expiring licenses $licenses = License::getExpiringLicenses($threshold); - - if ($licenses->count() > 0) { $this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold])); - \Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold)); + Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold)); } - - } else { - - if ($settings->alert_email=='') { + if ($settings->alert_email == '') { $this->error('Could not send email. No alert email configured in settings'); - } elseif ($settings->alerts_enabled!=1) { + } elseif (1 != $settings->alerts_enabled) { $this->info('Alerts are disabled in the settings. No mail will be sent'); } - } - - - - } } diff --git a/app/Console/Commands/SendInventoryAlerts.php b/app/Console/Commands/SendInventoryAlerts.php index cd9627e81a..93b04978b0 100644 --- a/app/Console/Commands/SendInventoryAlerts.php +++ b/app/Console/Commands/SendInventoryAlerts.php @@ -2,13 +2,12 @@ namespace App\Console\Commands; -use App\Models\Setting; -use DB; -use Mail; use App\Helpers\Helper; +use App\Models\Recipients\AlertRecipient; +use App\Models\Setting; use App\Notifications\InventoryAlert; - use Illuminate\Console\Command; +use Illuminate\Support\Facades\Notification; class SendInventoryAlerts extends Command { @@ -28,8 +27,6 @@ class SendInventoryAlerts extends Command /** * Create a new command instance. - * - * @return void */ public function __construct() { @@ -45,29 +42,24 @@ class SendInventoryAlerts extends Command { $settings = Setting::getSettings(); - if (($settings->alert_email!='') && ($settings->alerts_enabled==1)) { - + if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) { $items = Helper::checkLowInventory(); - // Send a rollup to the admin, if settings dictate - if (($items) && (count($items) > 0)) { $this->info(trans_choice('mail.low_inventory_alert', count($items))); // Send a rollup to the admin, if settings dictate $recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) { - return new \App\Models\Recipients\AlertRecipient($item); + return new AlertRecipient($item); }); - \Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold)); - } + Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold)); + } } else { - if (Setting::getSettings()->alert_email=='') { + if ($settings->alert_email == '') { $this->error('Could not send email. No alert email configured in settings'); - } elseif (Setting::getSettings()->alerts_enabled!=1) { + } elseif (1 != $settings->alerts_enabled) { $this->info('Alerts are disabled in the settings. No mail will be sent'); } } - - } } diff --git a/app/Console/Commands/SyncAssetCounters.php b/app/Console/Commands/SyncAssetCounters.php index 33fee840d6..33104818e1 100644 --- a/app/Console/Commands/SyncAssetCounters.php +++ b/app/Console/Commands/SyncAssetCounters.php @@ -2,8 +2,8 @@ namespace App\Console\Commands; -use Illuminate\Console\Command; use App\Models\Asset; +use Illuminate\Console\Command; class SyncAssetCounters extends Command { diff --git a/app/Console/Commands/SyncAssetLocations.php b/app/Console/Commands/SyncAssetLocations.php index ea22ad794b..b5d3cd33e0 100644 --- a/app/Console/Commands/SyncAssetLocations.php +++ b/app/Console/Commands/SyncAssetLocations.php @@ -2,10 +2,8 @@ namespace App\Console\Commands; -use App\Models\CustomField; -use Illuminate\Console\Command; use App\Models\Asset; -use Illuminate\Support\Facades\Storage; +use Illuminate\Console\Command; class SyncAssetLocations extends Command { diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 9be64cf339..1dcac211b2 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -19,7 +19,6 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - $schedule->command('snipeit:inventory-alerts')->daily(); $schedule->command('snipeit:expiring-alerts')->daily(); $schedule->command('snipeit:expected-checkin')->daily(); @@ -28,6 +27,10 @@ class Kernel extends ConsoleKernel $schedule->command('snipeit:upcoming-audits')->daily(); } + /** + * This method is required by Laravel to handle any console routes + * that are defined in routes/console.php. + */ protected function commands() { require base_path('routes/console.php'); diff --git a/app/Events/CheckoutAccepted.php b/app/Events/CheckoutAccepted.php new file mode 100644 index 0000000000..5146b32ee9 --- /dev/null +++ b/app/Events/CheckoutAccepted.php @@ -0,0 +1,23 @@ +acceptance = $acceptance; + } +} diff --git a/app/Events/CheckoutDeclined.php b/app/Events/CheckoutDeclined.php new file mode 100644 index 0000000000..44f399423f --- /dev/null +++ b/app/Events/CheckoutDeclined.php @@ -0,0 +1,23 @@ +acceptance = $acceptance; + } +} diff --git a/app/Events/CheckoutableCheckedIn.php b/app/Events/CheckoutableCheckedIn.php new file mode 100644 index 0000000000..54e3db6abc --- /dev/null +++ b/app/Events/CheckoutableCheckedIn.php @@ -0,0 +1,32 @@ +checkoutable = $checkoutable; + $this->checkedOutTo = $checkedOutTo; + $this->checkedInBy = $checkedInBy; + $this->note = $note; + $this->action_date = $action_date ?? date('Y-m-d'); + } +} diff --git a/app/Events/CheckoutableCheckedOut.php b/app/Events/CheckoutableCheckedOut.php new file mode 100644 index 0000000000..5e6ffd243a --- /dev/null +++ b/app/Events/CheckoutableCheckedOut.php @@ -0,0 +1,30 @@ +checkoutable = $checkoutable; + $this->checkedOutTo = $checkedOutTo; + $this->checkedOutBy = $checkedOutBy; + $this->note = $note; + } +} diff --git a/app/Exceptions/CheckoutNotAllowed.php b/app/Exceptions/CheckoutNotAllowed.php index 91bf2b865b..6fe2c1d484 100644 --- a/app/Exceptions/CheckoutNotAllowed.php +++ b/app/Exceptions/CheckoutNotAllowed.php @@ -3,6 +3,7 @@ namespace App\Exceptions; use Exception; + class CheckoutNotAllowed extends Exception { diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index a82d983cf5..a81f1a4644 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -9,6 +9,7 @@ use App\Helpers\Helper; use Illuminate\Validation\ValidationException; use Log; + class Handler extends ExceptionHandler { /** diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index b8ef8ccda6..e24f49f61e 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1,25 +1,16 @@ 'fa fa-file-image-o', + 'jpeg' => 'fa fa-file-image-o', + 'gif' => 'fa fa-file-image-o', + 'png' => 'fa fa-file-image-o', + // word + 'doc' => 'fa fa-file-word-o', + 'docx' => 'fa fa-file-word-o', + // Excel + 'xls' => 'fa fa-file-excel-o', + 'xlsx' => 'fa fa-file-excel-o', + // archive + 'zip' => 'fa fa-file-archive-o', + 'rar' => 'fa fa-file-archive-o', + //Text + 'txt' => 'fa fa-file-text-o', + 'rtf' => 'fa fa-file-text-o', + 'xml' => 'fa fa-file-text-o', + // Misc + 'pdf' => 'fa fa-file-pdf-o', + 'lic' => 'fa fa-file-floppy-o', + ]; + + if ($extension && array_key_exists($extension, $allowedExtensionMap)) { + return $allowedExtensionMap[$extension]; } return "fa fa-file-o"; } @@ -669,7 +655,80 @@ class Helper return false; } + /** + * Generate a random encrypted password. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return string + */ + public static function generateEncyrptedPassword(): string + { + return bcrypt(Helper::generateUnencryptedPassword()); + } + /** + * Get a random unencrypted password. + * + * @author Steffen Buehl + * + * @since 5.0.0 + * + * @return string + */ + public static function generateUnencryptedPassword(): string + { + $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $password = ''; + for ( $i = 0; $i < 20; $i++ ) { + $password .= substr( $chars, random_int( 0, strlen( $chars ) - 1 ), 1 ); + } + return $password; + } + + /** + * Process base64 encoded image data and save it on supplied path + * + * @param string $image_data base64 encoded image data with mime type + * @param string $save_path path to a folder where the image should be saved + * @return string path to uploaded image or false if something went wrong + */ + public static function processUploadedImage(String $image_data, String $save_path) { + if ($image_data != null && $save_path != null) { + // After modification, the image is prefixed by mime info like the following: + // data:image/jpeg;base64,; This causes the image library to be unhappy, so we need to remove it. + $header = explode(';', $image_data, 2)[0]; + // Grab the image type from the header while we're at it. + $extension = substr($header, strpos($header, '/')+1); + // Start reading the image after the first comma, postceding the base64. + $image = substr($image_data, strpos($image_data, ',')+1); + + $file_name = str_random(25).".".$extension; + + $directory= public_path($save_path); + // Check if the uploads directory exists. If not, try to create it. + if (!file_exists($directory)) { + mkdir($directory, 0755, true); + } + + $path = public_path($save_path.$file_name); + + try { + Image::make($image)->resize(500, 500, function ($constraint) { + $constraint->aspectRatio(); + $constraint->upsize(); + })->save($path); + } catch (\Exception $e) { + return false; + } + + return $file_name; + } + + return false; + } } diff --git a/app/Http/Controllers/Accessories/AccessoriesController.php b/app/Http/Controllers/Accessories/AccessoriesController.php new file mode 100755 index 0000000000..a96859d928 --- /dev/null +++ b/app/Http/Controllers/Accessories/AccessoriesController.php @@ -0,0 +1,207 @@ +] + * @see AccessoriesController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('index', Accessory::class); + return view('accessories/index'); + } + + + /** + * Returns a view with a form to create a new Accessory. + * + * @author [A. Gianotto] [] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create() + { + $this->authorize('create', Accessory::class); + $category_type = 'accessory'; + return view('accessories/edit')->with('category_type', $category_type) + ->with('item', new Accessory); + } + + + /** + * Validate and save new Accessory from form post + * + * @author [A. Gianotto] [] + * @param ImageUploadRequest $request + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(ImageUploadRequest $request) + { + $this->authorize(Accessory::class); + // create a new model instance + $accessory = new Accessory(); + + // Update the accessory data + $accessory->name = request('name'); + $accessory->category_id = request('category_id'); + $accessory->location_id = request('location_id'); + $accessory->min_amt = request('min_amt'); + $accessory->company_id = Company::getIdForCurrentUser(request('company_id')); + $accessory->order_number = request('order_number'); + $accessory->manufacturer_id = request('manufacturer_id'); + $accessory->model_number = request('model_number'); + $accessory->purchase_date = request('purchase_date'); + $accessory->purchase_cost = Helper::ParseFloat(request('purchase_cost')); + $accessory->qty = request('qty'); + $accessory->user_id = Auth::user()->id; + $accessory->supplier_id = request('supplier_id'); + + $accessory = $request->handleImages($accessory); + + // Was the accessory created? + if ($accessory->save()) { + // Redirect to the new accessory page + return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.create.success')); + } + return redirect()->back()->withInput()->withErrors($accessory->getErrors()); + } + + /** + * Return view for the Accessory update form, prepopulated with existing data + * + * @author [A. Gianotto] [] + * @param int $accessoryId + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit($accessoryId = null) + { + + if ($item = Accessory::find($accessoryId)) { + $this->authorize($item); + return view('accessories/edit', compact('item'))->with('category_type', 'accessory'); + } + + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); + + } + + + /** + * Save edited Accessory from form post + * + * @author [A. Gianotto] [] + * @param ImageUploadRequest $request + * @param int $accessoryId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function update(ImageUploadRequest $request, $accessoryId = null) + { + if (is_null($accessory = Accessory::find($accessoryId))) { + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); + } + + $this->authorize($accessory); + + // Update the accessory data + $accessory->name = request('name'); + $accessory->location_id = request('location_id'); + $accessory->min_amt = request('min_amt'); + $accessory->category_id = request('category_id'); + $accessory->company_id = Company::getIdForCurrentUser(request('company_id')); + $accessory->manufacturer_id = request('manufacturer_id'); + $accessory->order_number = request('order_number'); + $accessory->model_number = request('model_number'); + $accessory->purchase_date = request('purchase_date'); + $accessory->purchase_cost = request('purchase_cost'); + $accessory->qty = request('qty'); + $accessory->supplier_id = request('supplier_id'); + + $accessory = $request->handleImages($accessory); + + // Was the accessory updated? + if ($accessory->save()) { + return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success')); + } + return redirect()->back()->withInput()->withErrors($accessory->getErrors()); + } + + /** + * Delete the given accessory. + * + * @author [A. Gianotto] [] + * @param int $accessoryId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($accessoryId) + { + if (is_null($accessory = Accessory::find($accessoryId))) { + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found')); + } + + $this->authorize($accessory); + + + if ($accessory->hasUsers() > 0) { + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers()))); + } + + if ($accessory->image) { + try { + Storage::disk('public')->delete('accessories'.'/'.$accessory->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + + $accessory->delete(); + return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success')); + } + + + /** + * Returns a view that invokes the ajax table which contains + * the content for the accessory detail view, which is generated in getDataView. + * + * @author [A. Gianotto] [] + * @param int $accessoryID + * @see AccessoriesController::getDataView() method that generates the JSON response + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($accessoryID = null) + { + $accessory = Accessory::find($accessoryID); + $this->authorize('view', $accessory); + if (isset($accessory->id)) { + return view('accessories/view', compact('accessory')); + } + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist', ['id' => $accessoryID])); + } +} diff --git a/app/Http/Controllers/Accessories/AccessoryCheckinController.php b/app/Http/Controllers/Accessories/AccessoryCheckinController.php new file mode 100644 index 0000000000..1cfbaec1b4 --- /dev/null +++ b/app/Http/Controllers/Accessories/AccessoryCheckinController.php @@ -0,0 +1,78 @@ +] + * @param Request $request + * @param integer $accessoryUserId + * @param string $backto + * @return View + * @internal param int $accessoryId + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($accessoryUserId = null, $backto = null) + { + // Check if the accessory exists + 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')); + } + + $accessory = Accessory::find($accessory_user->accessory_id); + $this->authorize('checkin', $accessory); + return view('accessories/checkin', compact('accessory'))->with('backto', $backto); + } + + /** + * Check in the item so that it can be checked out again to someone else + * + * @uses Accessory::checkin_email() to determine if an email can and should be sent + * @author [A. Gianotto] [] + * @param null $accessoryUserId + * @param string $backto + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + * @internal param int $accessoryId + */ + public function store(Request $request, $accessoryUserId = null, $backto = null) + { + // Check if the accessory exists + 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')); + } + + $accessory = Accessory::find($accessory_user->accessory_id); + + $this->authorize('checkin', $accessory); + + $checkin_at = date('Y-m-d'); + if($request->filled('checkin_at')){ + $checkin_at = $request->input('checkin_at'); + } + + // Was the accessory updated? + if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) { + $return_to = e($accessory_user->assigned_to); + + 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')); + } + // Redirect to the accessory management page with error + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error')); + } +} diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php new file mode 100644 index 0000000000..a6cb745923 --- /dev/null +++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php @@ -0,0 +1,88 @@ +] + * @param int $accessoryId + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($accessoryId) + { + // Check if the accessory exists + if (is_null($accessory = Accessory::find($accessoryId))) { + // Redirect to the accessory management page with error + return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found')); + } + + if ($accessory->category) { + + $this->authorize('checkout', $accessory); + + // Get the dropdown of users and then pass it to the checkout view + return view('accessories/checkout', compact('accessory')); + } + + return redirect()->back()->with('error', 'The category type for this accessory is not valid. Edit the accessory and select a valid accessory category.'); + } + + /** + * Save the Accessory checkout information. + * + * If Slack is enabled and/or asset acceptance is enabled, it will also + * trigger a Slack message and send an email. + * + * @author [A. Gianotto] [] + * @param Request $request + * @param int $accessoryId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request, $accessoryId) + { + // Check if the accessory exists + if (is_null($accessory = Accessory::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); + + if (!$user = User::find($request->input('assigned_to'))) { + return redirect()->route('checkout/accessory', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist')); + } + + // 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') + ]); + + 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 + return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success')); + } +} diff --git a/app/Http/Controllers/AccessoriesController.php b/app/Http/Controllers/AccessoriesController.php deleted file mode 100755 index d70de63630..0000000000 --- a/app/Http/Controllers/AccessoriesController.php +++ /dev/null @@ -1,360 +0,0 @@ -] - * @see AccessoriesController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return View - */ - public function index(Request $request) - { - $this->authorize('index', Accessory::class); - return view('accessories/index'); - } - - - /** - * Returns a view with a form to create a new Accessory. - * - * @author [A. Gianotto] [] - * @return View - */ - public function create(Request $request) - { - $this->authorize('create', Accessory::class); - $category_type = 'accessory'; - return view('accessories/edit')->with('category_type', $category_type) - ->with('item', new Accessory); - } - - - /** - * Validate and save new Accessory from form post - * - * @author [A. Gianotto] [] - * @return Redirect - */ - public function store(ImageUploadRequest $request) - { - $this->authorize(Accessory::class); - // create a new model instance - $accessory = new Accessory(); - - // Update the accessory data - $accessory->name = request('name'); - $accessory->category_id = request('category_id'); - $accessory->location_id = request('location_id'); - $accessory->min_amt = request('min_amt'); - $accessory->company_id = Company::getIdForCurrentUser(request('company_id')); - $accessory->order_number = request('order_number'); - $accessory->manufacturer_id = request('manufacturer_id'); - $accessory->model_number = request('model_number'); - $accessory->purchase_date = request('purchase_date'); - $accessory->purchase_cost = Helper::ParseFloat(request('purchase_cost')); - $accessory->qty = request('qty'); - $accessory->user_id = Auth::user()->id; - $accessory->supplier_id = request('supplier_id'); - $accessory = $request->handleImages($accessory,600, public_path().'/uploads/accessories'); - - - // Was the accessory created? - if ($accessory->save()) { - // Redirect to the new accessory page - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.create.success')); - } - return redirect()->back()->withInput()->withErrors($accessory->getErrors()); - } - - /** - * Return view for the Accessory update form, prepopulated with existing data - * - * @author [A. Gianotto] [] - * @param int $accessoryId - * @return View - */ - public function edit(Request $request, $accessoryId = null) - { - - if ($item = Accessory::find($accessoryId)) { - $this->authorize($item); - $category_type = 'accessory'; - return view('accessories/edit', compact('item'))->with('category_type', $category_type); - } - - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); - - } - - - /** - * Save edited Accessory from form post - * - * @author [A. Gianotto] [] - * @param int $accessoryId - * @return Redirect - */ - public function update(ImageUploadRequest $request, $accessoryId = null) - { - if (is_null($accessory = Accessory::find($accessoryId))) { - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); - } - - $this->authorize($accessory); - - // Update the accessory data - $accessory->name = request('name'); - $accessory->location_id = request('location_id'); - $accessory->min_amt = request('min_amt'); - $accessory->category_id = request('category_id'); - $accessory->company_id = Company::getIdForCurrentUser(request('company_id')); - $accessory->manufacturer_id = request('manufacturer_id'); - $accessory->order_number = request('order_number'); - $accessory->model_number = request('model_number'); - $accessory->purchase_date = request('purchase_date'); - $accessory->purchase_cost = request('purchase_cost'); - $accessory->qty = request('qty'); - $accessory->supplier_id = request('supplier_id'); - - $accessory = $request->handleImages($accessory,600, public_path().'/uploads/accessories'); - - - // Was the accessory updated? - if ($accessory->save()) { - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success')); - } - return redirect()->back()->withInput()->withErrors($accessory->getErrors()); - } - - /** - * Delete the given accessory. - * - * @author [A. Gianotto] [] - * @param int $accessoryId - * @return Redirect - */ - public function destroy(Request $request, $accessoryId) - { - if (is_null($accessory = Accessory::find($accessoryId))) { - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found')); - } - - $this->authorize($accessory); - - - if ($accessory->hasUsers() > 0) { - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers()))); - } - $accessory->delete(); - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success')); - } - - - - /** - * Returns a view that invokes the ajax table which contains - * the content for the accessory detail view, which is generated in getDataView. - * - * @author [A. Gianotto] [] - * @param int $accessoryID - * @see AccessoriesController::getDataView() method that generates the JSON response - * @since [v1.0] - * @return View - */ - public function show(Request $request, $accessoryID = null) - { - $accessory = Accessory::find($accessoryID); - $this->authorize('view', $accessory); - if (isset($accessory->id)) { - return view('accessories/view', compact('accessory')); - } - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); - } - - /** - * Return the form to checkout an Accessory to a user. - * - * @author [A. Gianotto] [] - * @param int $accessoryId - * @return View - */ - public function getCheckout(Request $request, $accessoryId) - { - // Check if the accessory exists - if (is_null($accessory = Accessory::find($accessoryId))) { - // Redirect to the accessory management page with error - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found')); - } - - if ($accessory->category) { - - $this->authorize('checkout', $accessory); - - // Get the dropdown of users and then pass it to the checkout view - return view('accessories/checkout', compact('accessory')); - } - - return redirect()->back()->with('error', 'The category type for this accessory is not valid. Edit the accessory and select a valid accessory category.'); - - - - } - - /** - * Save the Accessory checkout information. - * - * If Slack is enabled and/or asset acceptance is enabled, it will also - * trigger a Slack message and send an email. - * - * @author [A. Gianotto] [] - * @param int $accessoryId - * @return Redirect - */ - public function postCheckout(Request $request, $accessoryId) - { - // Check if the accessory exists - if (is_null($accessory = Accessory::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); - - if (!$user = User::find(Input::get('assigned_to'))) { - return redirect()->route('checkout/accessory', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist')); - } - - // Update the accessory data - $accessory->assigned_to = e(Input::get('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') - ]); - - $logaction = $accessory->logCheckout(e(Input::get('note')), $user); - - DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first(); - - $data['log_id'] = $logaction->id; - $data['eula'] = $accessory->getEula(); - $data['first_name'] = $user->first_name; - $data['item_name'] = $accessory->name; - $data['checkout_date'] = $logaction->created_at; - $data['item_tag'] = ''; - $data['expected_checkin'] = ''; - $data['note'] = $logaction->note; - $data['require_acceptance'] = $accessory->requireAcceptance(); - - // Redirect to the new accessory page - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success')); - } - - - /** - * Check the accessory back into inventory - * - * @author [A. Gianotto] [] - * @param Request $request - * @param integer $accessoryUserId - * @param string $backto - * @return View - * @internal param int $accessoryId - */ - public function getCheckin(Request $request, $accessoryUserId = null, $backto = null) - { - // Check if the accessory exists - 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')); - } - - $accessory = Accessory::find($accessory_user->accessory_id); - $this->authorize('checkin', $accessory); - return view('accessories/checkin', compact('accessory'))->with('backto', $backto); - } - - - /** - * Check in the item so that it can be checked out again to someone else - * - * @uses Accessory::checkin_email() to determine if an email can and should be sent - * @author [A. Gianotto] [] - * @param Request $request - * @param integer $accessoryUserId - * @param string $backto - * @return Redirect - * @internal param int $accessoryId - */ - public function postCheckin(Request $request, $accessoryUserId = null, $backto = null) - { - // Check if the accessory exists - 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')); - } - - $accessory = Accessory::find($accessory_user->accessory_id); - - $this->authorize('checkin', $accessory); - - $return_to = e($accessory_user->assigned_to); - $logaction = $accessory->logCheckin(User::find($return_to), e(Input::get('note'))); - - // Was the accessory updated? - if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) { - if (!is_null($accessory_user->assigned_to)) { - $user = User::find($accessory_user->assigned_to); - } - - $data['log_id'] = $logaction->id; - $data['first_name'] = e($user->first_name); - $data['last_name'] = e($user->last_name); - $data['item_name'] = e($accessory->name); - $data['checkin_date'] = e($logaction->created_at); - $data['item_tag'] = ''; - $data['note'] = e($logaction->note); - - if ($backto=='user') { - return redirect()->route("users.show", $return_to)->with('success', trans('admin/accessories/message.checkin.success')); - } - return redirect()->route("accessories.show", $accessory->id)->with('success', trans('admin/accessories/message.checkin.success')); - } - // Redirect to the accessory management page with error - return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error')); - } - - -} diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php new file mode 100644 index 0000000000..2f829b4e82 --- /dev/null +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -0,0 +1,127 @@ +pending()->get(); + + return view('account/accept.index', compact('acceptances')); + } + + /** + * Shows a form to either accept or decline the checkout acceptance + * + * @param int $id + * @return mixed + */ + public function create($id) { + + $acceptance = CheckoutAcceptance::find($id); + + if (is_null($acceptance)) { + return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); + } + + if (! $acceptance->isPending()) { + return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted')); + } + + if (! $acceptance->isCheckedOutTo(Auth::user())) { + return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted')); + } + + if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) { + return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions')); + } + + return view('account/accept.create', compact('acceptance')); + } + + /** + * Stores the accept/decline of the checkout acceptance + * + * @param Request $request + * @param int $id + * @return Redirect + */ + public function store(Request $request, $id) { + + $acceptance = CheckoutAcceptance::find($id); + + if (is_null($acceptance)) { + return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); + } + + if (! $acceptance->isPending()) { + return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted')); + } + + if (! $acceptance->isCheckedOutTo(Auth::user())) { + return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted')); + } + + if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) { + return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions')); + } + + if (!$request->filled('asset_acceptance')) { + return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline')); + } + + /** + * Get the signature and save it + */ + + if (!Storage::exists('private_uploads/signatures')) Storage::makeDirectory('private_uploads/signatures', 775); + + + + if ($request->filled('signature_output')) { + $sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png"; + $data_uri = e($request->input('signature_output')); + $encoded_image = explode(",", $data_uri); + $decoded_image = base64_decode($encoded_image[1]); + Storage::put('private_uploads/signatures/'.$sig_filename, (string)$decoded_image); + } + + + if ($request->input('asset_acceptance') == 'accepted') { + + $acceptance->accept($sig_filename); + + event(new CheckoutAccepted($acceptance)); + + $return_msg = trans('admin/users/message.accepted'); + + } else { + + $acceptance->decline($sig_filename); + + event(new CheckoutDeclined($acceptance)); + + $return_msg = trans('admin/users/message.declined'); + + } + + return redirect()->to('account/accept')->with('success', $return_msg); + } +} diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index bd239a05d3..d921065a5f 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -2,16 +2,17 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Accessory; +use App\Http\Controllers\Controller; use App\Http\Transformers\AccessoriesTransformer; +use App\Http\Transformers\SelectlistTransformer; +use App\Models\Accessory; use App\Models\Company; use App\Models\User; use Carbon\Carbon; use Auth; use DB; +use Illuminate\Http\Request; class AccessoriesController extends Controller { @@ -141,18 +142,37 @@ class AccessoriesController extends Controller * @param int $id * @return \Illuminate\Http\Response */ - public function checkedout($id) + public function checkedout($id, Request $request) { $this->authorize('view', Accessory::class); - $accessory = Accessory::findOrFail($id); + $accessory = Accessory::with('lastCheckout')->findOrFail($id); if (!Company::isCurrentUserHasAccess($accessory)) { return ['total' => 0, 'rows' => []]; } + + $offset = request('offset', 0); + $limit = request('limit', 50); + + $accessory->lastCheckoutArray = $accessory->lastCheckout->toArray(); $accessory_users = $accessory->users; $total = $accessory_users->count(); - return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory_users, $total); + if($total < $offset){ + $offset = 0; + } + + $accessory_users = $accessory->users()->skip($offset)->take($limit)->get(); + + if ($request->filled('search')) { + $accessory_users = $accessory->users() + ->where('first_name', 'like', '%'.$request->input('search').'%') + ->orWhere('last_name', 'like', '%'.$request->input('search').'%') + ->get(); + $total = $accessory_users->count(); + } + + return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_users, $total); } @@ -167,7 +187,7 @@ class AccessoriesController extends Controller */ public function update(Request $request, $id) { - $this->authorize('edit', Accessory::class); + $this->authorize('update', Accessory::class); $accessory = Accessory::findOrFail($id); $accessory->fill($request->all()); @@ -290,4 +310,31 @@ class AccessoriesController extends Controller } + + /** + * Gets a paginated collection for the select2 menus + * + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $accessories = Accessory::select([ + 'accessories.id', + 'accessories.name' + ]); + + if ($request->filled('search')) { + $accessories = $accessories->where('accessories.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $accessories = $accessories->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($accessories); + } + + + } diff --git a/app/Http/Controllers/Api/AssetMaintenancesController.php b/app/Http/Controllers/Api/AssetMaintenancesController.php index fcf4c9f9a0..519c7c0737 100644 --- a/app/Http/Controllers/Api/AssetMaintenancesController.php +++ b/app/Http/Controllers/Api/AssetMaintenancesController.php @@ -9,7 +9,6 @@ use App\Models\AssetMaintenance; use App\Models\Company; use Auth; use Carbon\Carbon; -use Gate; use Illuminate\Http\Request; use Illuminate\Support\Facades\Input; @@ -34,10 +33,10 @@ class AssetMaintenancesController extends Controller */ public function index(Request $request) { - $maintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company', 'admin'); + $maintenances = AssetMaintenance::with('asset', 'asset.model','asset.location', 'supplier', 'asset.company', 'admin'); - if (Input::has('search')) { - $maintenances = $maintenances->TextSearch(e($request->input('search'))); + if ($request->filled('search')) { + $maintenances = $maintenances->TextSearch($request->input('search')); } if ($request->filled('asset_id')) { @@ -65,8 +64,8 @@ class AssetMaintenancesController extends Controller 'asset_name', 'user_id' ]; - $order = Input::get('order') === 'asc' ? 'asc' : 'desc'; - $sort = in_array(Input::get('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at'; + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + $sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at'; switch ($sort) { case 'user_id': diff --git a/app/Http/Controllers/Api/AssetModelsController.php b/app/Http/Controllers/Api/AssetModelsController.php index aaa6bced98..408a119882 100644 --- a/app/Http/Controllers/Api/AssetModelsController.php +++ b/app/Http/Controllers/Api/AssetModelsController.php @@ -1,15 +1,15 @@ authorize('view', AssetModel::class); - $allowed_columns = ['id','image','name','model_number','eol','notes','created_at','manufacturer','assets_count']; + $allowed_columns = ['id','image','name','model_number','eol','notes','created_at','manufacturer','requestable', 'assets_count']; $assetmodels = AssetModel::select([ 'models.id', @@ -38,6 +38,7 @@ class AssetModelsController extends Controller 'models.name', 'model_number', 'eol', + 'requestable', 'models.notes', 'models.created_at', 'category_id', @@ -153,7 +154,19 @@ class AssetModelsController extends Controller $this->authorize('update', AssetModel::class); $assetmodel = AssetModel::findOrFail($id); $assetmodel->fill($request->all()); - $assetmodel->fieldset_id = $request->get("custom_fieldset_id"); + + /** + * Allow custom_fieldset_id to override and populate fieldset_id. + * This is stupid, but required for legacy API support. + * + * I have no idea why we manually overrode that field name + * in previous versions. I assume there was a good reason for + * it, but I'll be damned if I can think of one. - snipe + */ + if ($request->filled('custom_fieldset_id')) { + $assetmodel->fieldset_id = $request->get("custom_fieldset_id"); + } + if ($assetmodel->save()) { return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.update.success'))); @@ -182,7 +195,7 @@ class AssetModelsController extends Controller if ($assetmodel->image) { try { - unlink(public_path().'/uploads/models/'.$assetmodel->image); + Storage::disk('public')->delete('assetmodels/'.$assetmodel->image); } catch (\Exception $e) { \Log::info($e); } @@ -239,7 +252,7 @@ class AssetModelsController extends Controller $assetmodel->use_text .= ' (#'.e($assetmodel->model_number).')'; } - $assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? url('/').'/uploads/models/'.$assetmodel->image : null; + $assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null; } return (new SelectlistTransformer)->transformSelectlist($assetmodels); diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 91e22e780f..4c4e2a8a92 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -1,37 +1,31 @@ filled('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : ''; + $offset = (($assets) && (request('offset') > $assets->count())) ? 0 : request('offset', 0); // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which @@ -181,7 +176,7 @@ class AssetsController extends Controller // I am sad. :( switch ($request->input('status')) { case 'Deleted': - $assets->withTrashed()->Deleted(); + $assets->onlyTrashed(); break; case 'Pending': $assets->join('status_labels AS status_alias',function ($join) { @@ -299,6 +294,7 @@ class AssetsController extends Controller $total = $assets->count(); $assets = $assets->skip($offset)->take($limit)->get(); + // dd($assets); return (new AssetsTransformer)->transformAssets($assets, $total); } @@ -313,7 +309,7 @@ class AssetsController extends Controller */ public function showByTag($tag) { - if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->where('asset_tag',$tag)->first()) { + if ($asset = Asset::with('assetstatus')->with('assignedTo')->where('asset_tag',$tag)->first()) { $this->authorize('view', $asset); return (new AssetsTransformer)->transformAsset($asset); } @@ -334,8 +330,7 @@ class AssetsController extends Controller $this->authorize('index', Asset::class); if ($assets = Asset::with('assetstatus')->with('assignedTo') ->withTrashed()->where('serial',$serial)->get()) { - - return (new AssetsTransformer)->transformAssets($assets, $assets->count()); + return (new AssetsTransformer)->transformAssets($assets, $assets->count()); } return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200); @@ -352,13 +347,22 @@ class AssetsController extends Controller */ public function show($id) { - if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as userRequests_count')->findOrFail($id)) { + if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed() + ->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')->findOrFail($id)) { $this->authorize('view', $asset); return (new AssetsTransformer)->transformAsset($asset); } } + public function licenses($id) + { + $this->authorize('view', Asset::class); + $this->authorize('view', License::class); + $asset = Asset::where('id', $id)->withTrashed()->first(); + $licenses = $asset->licenses()->get(); + return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count()); + } /** @@ -380,7 +384,7 @@ class AssetsController extends Controller 'assets.assigned_to', 'assets.assigned_type', 'assets.status_id' - ])->with('model', 'assetstatus', 'assignedTo')->NotArchived(),'company_id', 'assets'); + ])->with('model', 'assetstatus', 'assignedTo')->NotArchived(), 'company_id', 'assets'); if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') { $assets = $assets->RTD(); @@ -426,7 +430,7 @@ class AssetsController extends Controller * @since [v4.0] * @return JsonResponse */ - public function store(AssetRequest $request) + public function store(Request $request) { $this->authorize('create', Asset::class); @@ -455,6 +459,22 @@ class AssetsController extends Controller $asset->rtd_location_id = $request->get('rtd_location_id', null); $asset->location_id = $request->get('rtd_location_id', null); + if ($request->has('image_source') && $request->input('image_source') != "") { + $saved_image_path = Helper::processUploadedImage( + $request->input('image_source'), 'uploads/assets/' + ); + + if (!$saved_image_path) { + return response()->json(Helper::formatStandardApiResponse( + 'error', + null, + trans('admin/hardware/message.create.error') + ), 200); + } + + $asset->image = $saved_image_path; + } + // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request $model = AssetModel::find($request->get('model_id')); @@ -482,6 +502,11 @@ class AssetsController extends Controller if (isset($target)) { $asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name'))); } + + if ($asset->image) { + $asset->image = $asset->getImageUrl(); + } + return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success'))); } @@ -502,15 +527,40 @@ class AssetsController extends Controller $this->authorize('update', Asset::class); if ($asset = Asset::find($id)) { - $asset->fill($request->all()); ($request->filled('model_id')) ? $asset->model()->associate(AssetModel::find($request->get('model_id'))) : null; + ($request->filled('rtd_location_id')) ? + $asset->location_id = $request->get('rtd_location_id') : ''; ($request->filled('company_id')) ? - $asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : null; + $asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : ''; + +($request->filled('rtd_location_id')) ? + $asset->location_id = $request->get('rtd_location_id') : null; + + + if ($request->filled('image_source')) { + if ($request->input('image_source') == "") { ($request->filled('rtd_location_id')) ? $asset->location_id = $request->get('rtd_location_id') : null; + $asset->image = null; + } else { + $saved_image_path = Helper::processUploadedImage( + $request->input('image_source'), 'uploads/assets/' + ); + + if (!$saved_image_path) { + return response()->json(Helper::formatStandardApiResponse( + 'error', + null, + trans('admin/hardware/message.update.error') + ), 200); + } + + $asset->image = $saved_image_path; + } + } // Update custom fields if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) { @@ -531,7 +581,7 @@ class AssetsController extends Controller if ($asset->save()) { if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) { - $location = $target->location_id; + $location = $target->location_id; } elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) { $location = $target->location_id; @@ -546,6 +596,10 @@ class AssetsController extends Controller $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) { + $asset->image = $asset->getImageUrl(); + } + return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200); @@ -650,6 +704,7 @@ class AssetsController extends Controller // Wait, why are we doing this? This overrides the stuff we set further up, which makes no sense. // TODO: Follow up here. WTF. Commented out for now. + // if ((isset($target->rtd_location_id)) && ($asset->rtd_location_id!='')) { // $asset->location_id = $target->rtd_location_id; // } @@ -700,12 +755,12 @@ class AssetsController extends Controller $asset->location_id = $request->input('location_id'); } - if (Input::has('status_id')) { - $asset->status_id = Input::get('status_id'); + if ($request->has('status_id')) { + $asset->status_id = $request->input('status_id'); } if ($asset->save()) { - $asset->logCheckin($target, e(request('note'))); + $asset->logCheckin($target, e($request->input('note'))); return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success'))); } @@ -736,13 +791,27 @@ class AssetsController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all())); } + $settings = Setting::getSettings(); + $dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString(); + $asset = Asset::where('asset_tag','=', $request->input('asset_tag'))->first(); if ($asset) { // We don't want to log this as a normal update, so let's bypass that $asset->unsetEventDispatcher(); - $asset->next_audit_date = $request->input('next_audit_date'); + $asset->next_audit_date = $dt; + + if ($request->filled('next_audit_date')) { + $asset->next_audit_date = $request->input('next_audit_date'); + } + + // Check to see if they checked the box to update the physical location, + // not just note it in the audit notes + if ($request->input('update_location')=='1') { + $asset->location_id = $request->input('location_id'); + } + $asset->last_audit_date = date('Y-m-d h:i:s'); if ($asset->save()) { @@ -750,7 +819,7 @@ class AssetsController extends Controller return response()->json(Helper::formatStandardApiResponse('success', [ 'asset_tag'=> e($asset->asset_tag), 'note'=> e($request->input('note')), - 'next_audit_date' => Helper::getFormattedDateObject($log->calcNextAuditDate()) + 'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date) ], trans('admin/hardware/message.audit.success'))); } } diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index 52d107f1a3..ae085c0f35 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -2,12 +2,13 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Category; +use App\Http\Controllers\Controller; use App\Http\Transformers\CategoriesTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\Category; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class CategoriesController extends Controller { @@ -121,14 +122,10 @@ class CategoriesController extends Controller $this->authorize('delete', Category::class); $category = Category::findOrFail($id); - if ($category->has_models() > 0) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'model']))); - } elseif ($category->accessories()->count() > 0) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory']))); - } elseif ($category->consumables()->count() > 0) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable']))); - } elseif ($category->components()->count() > 0) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'component']))); + if (!$category->isDeletable()) { + return response()->json( + Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>$category->category_type])) + ); } $category->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success'))); @@ -163,7 +160,7 @@ class CategoriesController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($categories as $category) { - $category->use_image = ($category->image) ? url('/').'/uploads/categories/'.$category->image : null; + $category->use_image = ($category->image) ? Storage::disk('public')->url('categories/'.$category->image, $category->image) : null; } return (new SelectlistTransformer)->transformSelectlist($categories); diff --git a/app/Http/Controllers/Api/CompaniesController.php b/app/Http/Controllers/Api/CompaniesController.php index 7b4781e2c8..c56ed9f871 100644 --- a/app/Http/Controllers/Api/CompaniesController.php +++ b/app/Http/Controllers/Api/CompaniesController.php @@ -2,12 +2,13 @@ namespace App\Http\Controllers\Api; -use App\Http\Transformers\CompaniesTransformer; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Company; +use App\Http\Controllers\Controller; +use App\Http\Transformers\CompaniesTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\Company; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class CompaniesController extends Controller { @@ -47,7 +48,7 @@ class CompaniesController extends Controller // Check to make sure the limit is not higher than the max allowed ((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results'); - + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at'; $companies->orderBy($sort, $order); @@ -132,28 +133,17 @@ class CompaniesController extends Controller */ public function destroy($id) { - $this->authorize('delete', Company::class); - $company = Company::findOrFail($id); - $this->authorize('delete', $company); + $this->authorize('delete', Company::class); + $company = Company::findOrFail($id); + $this->authorize('delete', $company); - try { - $company->delete(); + if ( !$company->isDeletable() ) { return response() - ->json(Helper::formatStandardApiResponse('success', null, trans('admin/companies/message.delete.success'))); - } catch (\Illuminate\Database\QueryException $exception) { - /* - * NOTE: This happens when there's a foreign key constraint violation - * For example when rows in other tables are referencing this company - */ - if ($exception->getCode() == 23000) { - return response() ->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users'))); - - } else { - throw $exception; - } } - + $company->delete(); + return response() + ->json(Helper::formatStandardApiResponse('success', null, trans('admin/companies/message.delete.success'))); } /** @@ -183,7 +173,7 @@ class CompaniesController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($companies as $company) { - $company->use_image = ($company->image) ? url('/').'/uploads/companies/'.$company->image : null; + $company->use_image = ($company->image) ? Storage::disk('public')->url('companies/'.$company->image, $company->image) : null; } return (new SelectlistTransformer)->transformSelectlist($companies); diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index d1e8ed1b89..d7af18b21c 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -2,14 +2,12 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; -use App\Http\Transformers\AssetsTransformer; -use App\Http\Transformers\ComponentsTransformer; -use App\Http\Transformers\ComponentsAssetsTransformer; -use App\Models\Component; -use App\Models\Company; use App\Helpers\Helper; +use App\Http\Controllers\Controller; +use App\Http\Transformers\ComponentsTransformer; +use App\Models\Company; +use App\Models\Component; +use Illuminate\Http\Request; class ComponentsController extends Controller { diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index e7b15c4f24..e67215a00d 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -2,13 +2,14 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; +use App\Helpers\Helper; use App\Http\Controllers\Controller; +use App\Http\Transformers\ConsumablesTransformer; +use App\Http\Transformers\SelectlistTransformer; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use App\Http\Transformers\ConsumablesTransformer; -use App\Helpers\Helper; +use Illuminate\Http\Request; class ConsumablesController extends Controller { @@ -162,7 +163,7 @@ class ConsumablesController extends Controller * Returns a JSON response containing details on the users associated with this consumable. * * @author [A. Gianotto] [] - * @see ConsumablesController::getView() method that returns the form. + * @see \App\Http\Controllers\Consumables\ConsumablesController::getView() method that returns the form. * @since [v1.0] * @param int $consumableId * @return array @@ -248,4 +249,28 @@ class ConsumablesController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, 'No consumables remaining')); } + + /** + * Gets a paginated collection for the select2 menus + * + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $consumables = Consumable::select([ + 'consumables.id', + 'consumables.name' + ]); + + if ($request->filled('search')) { + $consumables = $consumables->where('consumables.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $consumables = $consumables->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($consumables); + } } diff --git a/app/Http/Controllers/Api/CustomFieldsController.php b/app/Http/Controllers/Api/CustomFieldsController.php index 4a7f24f53c..8feb2a1160 100644 --- a/app/Http/Controllers/Api/CustomFieldsController.php +++ b/app/Http/Controllers/Api/CustomFieldsController.php @@ -9,7 +9,6 @@ use App\Models\CustomField; use App\Models\CustomFieldset; use Illuminate\Http\Request; use Validator; -use Illuminate\Validation\Rule; class CustomFieldsController extends Controller { @@ -59,9 +58,9 @@ class CustomFieldsController extends Controller { $this->authorize('update', CustomField::class); $field = CustomField::findOrFail($id); - + /** - * Updated values for the field, + * Updated values for the field, * without the "field_encrypted" flag, preventing the change of encryption status * @var array */ diff --git a/app/Http/Controllers/Api/CustomFieldsetsController.php b/app/Http/Controllers/Api/CustomFieldsetsController.php index ab07081039..321959b9fd 100644 --- a/app/Http/Controllers/Api/CustomFieldsetsController.php +++ b/app/Http/Controllers/Api/CustomFieldsetsController.php @@ -1,22 +1,14 @@ transformDepartment($department); } + /** + * Update the specified resource in storage. + * + * @author [A. Gianotto] [] + * @since [v5.0] + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $this->authorize('update', Department::class); + $department = Department::findOrFail($id); + $department->fill($request->all()); + + if ($department->save()) { + return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.update.success'))); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors())); + } + /** - * Validates and deletes selected location. + * Validates and deletes selected department. * * @author [A. Gianotto] [] * @param int $locationId - * @since [v1.0] + * @since [v4.0] * @return \Illuminate\Http\RedirectResponse */ public function destroy($id) @@ -157,34 +180,11 @@ class DepartmentsController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($departments as $department) { - $department->use_image = ($department->image) ? url('/').'/uploads/departments/'.$department->image : null; + $department->use_image = ($department->image) ? Storage::disk('public')->url('departments/'.$department->image, $department->image) : null; } return (new SelectlistTransformer)->transformSelectlist($departments); } - /** - * Update the specified resource in storage. - * - * @author [Godfrey Martinez] [] - * @since [v4.0] - * @param \Illuminate\Http\Request $request - * @param int $id - * @return \Illuminate\Http\Response - */ - public function update(Request $request, $id) - { - $this->authorize('update', Department::class); - $departments = Department::findOrFail($id); - $departments->fill($request->all()); - - if ($departments->save()) { - return response() - ->json(Helper::formatStandardApiResponse('success', (new DepartmentsTransformer())->transformdepartment($departments), trans('admin/departments/message.update.success'))); - } - - return response() - ->json(Helper::formatStandardApiResponse('error', null, $departments->getErrors())); - } } diff --git a/app/Http/Controllers/Api/DepreciationsController.php b/app/Http/Controllers/Api/DepreciationsController.php index 0cd4219a2e..95fcd5c94c 100644 --- a/app/Http/Controllers/Api/DepreciationsController.php +++ b/app/Http/Controllers/Api/DepreciationsController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Depreciation; +use App\Http\Controllers\Controller; use App\Http\Transformers\DepreciationsTransformer; +use App\Models\Depreciation; +use Illuminate\Http\Request; class DepreciationsController extends Controller { @@ -115,10 +115,10 @@ class DepreciationsController extends Controller public function destroy($id) { $this->authorize('delete', Depreciation::class); - $depreciation = Depreciation::findOrFail($id); + $depreciation = Depreciation::withCount('models as models_count')->findOrFail($id); $this->authorize('delete', $depreciation); - if ($depreciation->has_models() > 0) { + if ($depreciation->models_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', trans('admin/depreciations/message.assoc_users'))); } diff --git a/app/Http/Controllers/Api/GroupsController.php b/app/Http/Controllers/Api/GroupsController.php index 7fe150a422..120dbfe3bd 100644 --- a/app/Http/Controllers/Api/GroupsController.php +++ b/app/Http/Controllers/Api/GroupsController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Group; +use App\Http\Controllers\Controller; use App\Http\Transformers\GroupsTransformer; +use App\Models\Group; +use Illuminate\Http\Request; class GroupsController extends Controller { diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index f6520e33bd..2f88e3f474 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -6,15 +6,15 @@ use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\ItemImportRequest; use App\Http\Transformers\ImportsTransformer; +use App\Models\Asset; use App\Models\Company; use App\Models\Import; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Input; +use Artisan; +use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Session; +use Illuminate\Support\Facades\Storage; use League\Csv\Reader; use Symfony\Component\HttpFoundation\File\Exception\FileException; -use Artisan; -use App\Models\Asset; class ImportController extends Controller { @@ -41,7 +41,7 @@ class ImportController extends Controller { $this->authorize('import'); if (!config('app.lock_passwords')) { - $files = Input::file('files'); + $files = Request::file('files'); $path = config('app.private_uploads').'/imports'; $results = []; $import = new Import; @@ -112,14 +112,14 @@ class ImportController extends Controller /** * Processes the specified Import. * - * @param \App\Import $import + * @param int $import_id * @return \Illuminate\Http\Response */ public function process(ItemImportRequest $request, $import_id) { $this->authorize('import'); - // Run a backup immediately before processing + // Run a backup immediately before processing if ($request->has('run-backup')) { \Log::debug('Backup manually requested via importer'); Artisan::call('backup:run'); @@ -162,19 +162,26 @@ class ImportController extends Controller /** * Remove the specified resource from storage. * - * @param \App\Import $import + * @param int $import_id * @return \Illuminate\Http\Response */ public function destroy($import_id) { - $this->authorize('import'); - $import = Import::find($import_id); - try { - unlink(config('app.private_uploads').'/imports/'.$import->file_path); - $import->delete(); - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success'))); - } catch (\Exception $e) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.import.file_delete_error')), 500); + $this->authorize('create', Asset::class); + + if ($import = Import::find($import_id)) { + try { + // Try to delete the file + Storage::delete('imports/'.$import->file_path); + $import->delete(); + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success'))); + + } catch (\Exception $e) { + // If the file delete didn't work, remove it from the database anyway and return a warning + $import->delete(); + return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning'))); + } } + } } diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index a16dd4fa83..2a3d004d1f 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -6,6 +6,7 @@ use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Transformers\LicenseSeatsTransformer; use App\Http\Transformers\LicensesTransformer; +use App\Http\Transformers\SelectlistTransformer; use App\Models\Company; use App\Models\License; use App\Models\LicenseSeat; @@ -155,7 +156,7 @@ class LicensesController extends Controller public function show($id) { $this->authorize('view', License::class); - $license = License::findOrFail($id); + $license = License::withCount('freeSeats')->findOrFail($id); $license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset'); return (new LicensesTransformer)->transformLicense($license); } @@ -230,8 +231,8 @@ class LicensesController extends Controller $this->authorize('view', $license); - $seats = LicenseSeat::where('license_seats.license_id', $licenseId) - ->with('license', 'user', 'asset', 'user.department'); + $seats = LicenseSeat::with('license', 'user', 'asset', 'user.department') + ->where('license_seats.license_id', $licenseId); $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; @@ -241,10 +242,11 @@ class LicensesController extends Controller $seats->orderBy('id', $order); } - $total = $seats->count(); - $offset = (($seats) && (request('offset') > $total)) ? 0 : request('offset', 0); + $offset = (($seats) && (request('offset') > $seats->count())) ? 0 : request('offset', 0); $limit = request('limit', 50); + $total = $seats->count(); + $seats = $seats->skip($offset)->take($limit)->get(); if ($seats) { @@ -257,5 +259,29 @@ class LicensesController extends Controller } + + /** + * Gets a paginated collection for the select2 menus + * + * @see \App\Http\Transformers\SelectlistTransformer + */ + public function selectlist(Request $request) + { + + $licenses = License::select([ + 'licenses.id', + 'licenses.name' + ]); + + if ($request->filled('search')) { + $licenses = $licenses->where('licenses.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $licenses = $licenses->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($licenses); + } + } diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index d634f59599..cd2917b4f3 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -24,9 +24,9 @@ class LocationsController extends Controller { $this->authorize('view', Location::class); $allowed_columns = [ - 'id','name','address','address2','city','state','country','zip','created_at', - 'updated_at','manager_id','image', - 'assigned_assets_count','users_count','assets_count','currency']; + 'id','name','address','address2','city','state','country','zip','created_at', + 'updated_at','manager_id','image', + 'assigned_assets_count','users_count','assets_count','currency']; $locations = Location::with('parent', 'manager', 'children')->select([ 'locations.id', @@ -44,17 +44,16 @@ class LocationsController extends Controller 'locations.image', 'locations.currency' ])->withCount('assignedAssets as assigned_assets_count') - ->withCount('assets as assets_count') - ->withCount('users as users_count'); + ->withCount('assets as assets_count') + ->withCount('users as users_count'); if ($request->filled('search')) { $locations = $locations->TextSearch($request->input('search')); } - // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which - // case we override with the actual count, so we should return 0 items. - $offset = (($locations) && ($request->get('offset') > $locations->count())) ? $locations->count() : $request->get('offset', 0); + + $offset = (($locations) && (request('offset') > $locations->count())) ? 0 : request('offset', 0); // Check to make sure the limit is not higher than the max allowed ((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results'); @@ -143,22 +142,19 @@ class LocationsController extends Controller * @since [v4.0] * @param \Illuminate\Http\Request $request * @param int $id - * @return \Illuminate\Http\Response + * @return \Illuminate\Http\JsonResponse */ public function update(Request $request, $id) { $this->authorize('update', Location::class); $location = Location::findOrFail($id); - if ($request->input('parent_id') == $id) { - - return response()->json(Helper::formatStandardApiResponse('error', null, 'A location cannot be its own parent. Please select a different parent ID.')); - } - - $location->fill($request->all()); - if ($location->save()) { + + if ($location->isValid()) { + + $location->save(); return response()->json( Helper::formatStandardApiResponse( 'success', @@ -183,6 +179,10 @@ class LocationsController extends Controller { $this->authorize('delete', Location::class); $location = Location::findOrFail($id); + if(!$location->isDeletable()) { + return response() + ->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users'))); + } $this->authorize('delete', $location); $location->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success'))); diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index 463219f63b..6b9212137f 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -2,13 +2,13 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Manufacturer; -use App\Http\Transformers\DatatablesTransformer; +use App\Http\Controllers\Controller; use App\Http\Transformers\ManufacturersTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\Manufacturer; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class ManufacturersController extends Controller { @@ -123,11 +123,21 @@ class ManufacturersController extends Controller */ public function destroy($id) { + $this->authorize('delete', Manufacturer::class); $manufacturer = Manufacturer::findOrFail($id); $this->authorize('delete', $manufacturer); - $manufacturer->delete(); - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success'))); + + if ($manufacturer->isDeletable()) { + $manufacturer->delete(); + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success'))); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.assoc_users'))); + + + + } @@ -159,7 +169,7 @@ class ManufacturersController extends Controller // they may not have a ->name value but we want to display something anyway foreach ($manufacturers as $manufacturer) { $manufacturer->use_text = $manufacturer->name; - $manufacturer->use_image = ($manufacturer->image) ? url('/').'/uploads/manufacturers/'.$manufacturer->image : null; + $manufacturer->use_image = ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.$manufacturer->image, $manufacturer->image) : null; } return (new SelectlistTransformer)->transformSelectlist($manufacturers); diff --git a/app/Http/Controllers/Api/PredefinedKitsController.php b/app/Http/Controllers/Api/PredefinedKitsController.php new file mode 100644 index 0000000000..6d6f2797f1 --- /dev/null +++ b/app/Http/Controllers/Api/PredefinedKitsController.php @@ -0,0 +1,449 @@ +] + */ +class PredefinedKitsController extends Controller +{ + /** + * Display a listing of the resource. + * + * @return \Illuminate\Http\Response + */ + public function index(Request $request) + { + $this->authorize('view', PredefinedKit::class); + $allowed_columns = ['id', 'name']; + + $kits = PredefinedKit::query(); + + if ($request->filled('search')) { + $kits = $kits->TextSearch($request->input('search')); + } + + $offset = $request->input('offset', 0); + $limit = $request->input('limit', 50); + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets_count'; + $kits->orderBy($sort, $order); + + $total = $kits->count(); + $kits = $kits->skip($offset)->take($limit)->get(); + return (new PredefinedKitsTransformer)->transformPredefinedKits($kits, $total); + + } + + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + $this->authorize('create', PredefinedKit::class); + $kit = new PredefinedKit; + $kit->fill($request->all()); + + if ($kit->save()) { + return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.create_success'))); + } + return response()->json(Helper::formatStandardApiResponse('error', null, $kit->getErrors())); + + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + return (new PredefinedKitsTransformer)->transformPredefinedKit($kit); + } + + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id kit id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + $kit->fill($request->all()); + + if ($kit->save()) { + return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.update_success'))); // TODO: trans + } + + return response()->json(Helper::formatStandardApiResponse('error', null, $kit->getErrors())); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + $this->authorize('delete', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + + // Delete childs + $kit->models()->detach(); + $kit->licenses()->detach(); + $kit->consumables()->detach(); + $kit->accessories()->detach(); + + $kit->delete(); + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/kits/general.delete_success'))); // TODO: trans + + } + + + /** + * Gets a paginated collection for the select2 menus + * + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $kits = PredefinedKit::select([ + 'id', + 'name' + ]); + + if ($request->filled('search')) { + $kits = $kits->where('name', 'LIKE', '%'.$request->get('search').'%'); + } + + $kits = $kits->orderBy('name', 'ASC')->paginate(50); + + return (new SelectlistTransformer)->transformSelectlist($kits); + + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function indexLicenses($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $licenses = $kit->licenses; + return (new PredefinedKitsTransformer)->transformElements($licenses, $licenses->count()); + } + + + /** + * Store the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function storeLicense(Request $request, $kit_id) + { + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $license_id = $request->get('license'); + $relation = $kit->licenses(); + if( $relation->find($license_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['license' => 'License already attached to kit'])); + } + + $relation->attach( $license_id, ['quantity' => $quantity]); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License added successfull')); // TODO: trans + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function updateLicense(Request $request, $kit_id, $license_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->licenses()->syncWithoutDetaching([$license_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachLicense($kit_id, $license_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + + $kit->licenses()->detach($license_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.delete_success'))); + } + + /** + * Display the specified resource. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function indexModels($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $models = $kit->models; + return (new PredefinedKitsTransformer)->transformElements($models, $models->count()); + } + + /** + * Store the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function storeModel(Request $request, $kit_id) + { + + + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + + $model_id = $request->get('model'); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $relation = $kit->models(); + if( $relation->find($model_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['model' => 'Model already attached to kit'])); + } + $relation->attach($model_id, ['quantity' => $quantity]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Model added successfull')); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function updateModel(Request $request, $kit_id, $model_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->models()->syncWithoutDetaching([$model_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachModel($kit_id, $model_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + + $kit->models()->detach($model_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, trans('admin/kits/general.model_removed_success'))); + } + + + + /** + * Display the specified resource. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function indexConsumables($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $consumables = $kit->consumables; + return (new PredefinedKitsTransformer)->transformElements($consumables, $consumables->count()); + } + + + /** + * Store the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function storeConsumable(Request $request, $kit_id) + { + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $consumable_id = $request->get('consumable'); + $relation = $kit->consumables(); + if( $relation->find($consumable_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['consumable' => 'Consumable already attached to kit'])); + } + + $relation->attach( $consumable_id, ['quantity' => $quantity]); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable added successfull')); // TODO: trans + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function updateConsumable(Request $request, $kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->consumables()->syncWithoutDetaching([$consumable_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachConsumable($kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + + $kit->consumables()->detach($consumable_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans + } + + + /** + * Display the specified resource. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function indexAccessories($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $accessories = $kit->accessories; + return (new PredefinedKitsTransformer)->transformElements($accessories, $accessories->count()); + } + + + /** + * Store the specified resource. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function storeAccessory(Request $request, $kit_id) + { + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $accessory_id = $request->get('accessory'); + $relation = $kit->accessories(); + if( $relation->find($accessory_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['accessory' => 'Accessory already attached to kit'])); + } + + $relation->attach( $accessory_id, ['quantity' => $quantity]); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory added successfull')); // TODO: trans + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function updateAccessory(Request $request, $kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->accessories()->syncWithoutDetaching([$accessory_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachAccessory($kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + + $kit->accessories()->detach($accessory_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans + } +} diff --git a/app/Http/Controllers/Api/ProfileController.php b/app/Http/Controllers/Api/ProfileController.php index 0798381884..f6c31d5db1 100644 --- a/app/Http/Controllers/Api/ProfileController.php +++ b/app/Http/Controllers/Api/ProfileController.php @@ -2,11 +2,10 @@ namespace App\Http\Controllers\Api; -use App\Models\CheckoutRequest; -use App\Http\Controllers\Controller; -use Auth; use App\Helpers\Helper; - +use App\Http\Controllers\Controller; +use App\Models\CheckoutRequest; +use Auth; class ProfileController extends Controller { diff --git a/app/Http/Controllers/Api/ReportsController.php b/app/Http/Controllers/Api/ReportsController.php index e1b6ddd813..b29c327345 100644 --- a/app/Http/Controllers/Api/ReportsController.php +++ b/app/Http/Controllers/Api/ReportsController.php @@ -2,10 +2,10 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; use App\Http\Controllers\Controller; -use App\Models\Actionlog; use App\Http\Transformers\ActionlogsTransformer; +use App\Models\Actionlog; +use Illuminate\Http\Request; class ReportsController extends Controller { diff --git a/app/Http/Controllers/Api/SettingsController.php b/app/Http/Controllers/Api/SettingsController.php index 5c8b617199..b3c91cafc1 100644 --- a/app/Http/Controllers/Api/SettingsController.php +++ b/app/Http/Controllers/Api/SettingsController.php @@ -2,122 +2,122 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; use App\Http\Controllers\Controller; -use App\Models\Ldap; -use Validator; +use App\Http\Transformers\LoginAttemptsTransformer; use App\Models\Setting; -use Mail; -use App\Notifications\SlackTest; -use Notification; use App\Notifications\MailTest; +use App\Services\LdapAd; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Notification; +use GuzzleHttp\Client; class SettingsController extends Controller { - - public function ldaptest() + /** + * Test the ldap settings + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param App\Models\LdapAd $ldap + * + * @return \Illuminate\Http\JsonResponse + */ + public function ldapAdSettingsTest(LdapAd $ldap): JsonResponse { - - if (Setting::getSettings()->ldap_enabled!='1') { - \Log::debug('LDAP is not enabled so cannot test.'); - return response()->json(['message' => 'LDAP is not enabled, so we cannot test LDAP connections.'], 400); + if(!$ldap->init()) { + Log::info('LDAP is not enabled cannot test.'); + return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400); } - \Log::debug('Preparing to test LDAP connection'); + // The connect, bind and resulting users message + $message = []; + Log::info('Preparing to test LDAP user login'); + // Test user can connect to the LDAP server try { - $connection = Ldap::connectToLdap(); - try { - \Log::debug('attempting to bind to LDAP for LDAP test'); - Ldap::bindAdminToLdap($connection); - return response()->json(['message' => 'It worked!'], 200); - } catch (\Exception $e) { + $ldap->testLdapAdUserConnection(); + $message['login'] = [ + 'message' => 'Successfully connected to LDAP server.' + ]; + } catch (\Exception $ex) { \Log::debug('LDAP connected but Bind failed. Please check your LDAP settings and try again.'); - return response()->json(['message' => $e->getMessage()], 400); - //return response()->json(['message' => $e->getMessage()], 500); - } + return response()->json([ + 'message' => 'Error logging into LDAP server, error: ' . $ex->getMessage() . ' - Verify your that your username and password are correct']); + } catch (\Exception $e) { \Log::info('LDAP connection failed but we cannot debug it any further on our end.'); return response()->json(['message' => 'The LDAP connection failed but we cannot debug it any further on our end. The error from the server is: '.$e->getMessage()], 500); } + Log::info('Preparing to test LDAP bind connection'); + // Test user can bind to the LDAP server + try { + Log::info('Testing Bind'); + $ldap->testLdapAdBindConnection(); + $message['bind'] = [ + 'message' => 'Successfully binded to LDAP server.' + ]; + } catch (\Exception $ex) { + Log::info('LDAP Bind failed'); + return response()->json([ + 'message' => 'Error binding to LDAP server, error: ' . $ex->getMessage() + ], 400); + } + + Log::info('Preparing to get sample user set from LDAP directory'); + // Get a sample of 10 users so user can verify the data is correct + try { + Log::info('Testing LDAP sync'); + error_reporting(E_ALL & ~E_DEPRECATED); // workaround for php7.4, which deprecates ldap_control_paged_result + $users = $ldap->testUserImportSync(); + $message['user_sync'] = [ + 'users' => $users + ]; + } catch (\Exception $ex) { + Log::info('LDAP sync failed'); + $message['user_sync'] = [ + 'message' => 'Error getting users from LDAP directory, error: ' . $ex->getMessage() + ]; + return response()->json($message, 400); + } + + return response()->json($message, 200); } - public function ldaptestlogin(Request $request) + public function slacktest(Request $request) { - if (Setting::getSettings()->ldap_enabled!='1') { - \Log::debug('LDAP is not enabled. Cannot test.'); - return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400); - } + $slack = new Client([ + 'base_url' => e($request->input('slack_endpoint')), + 'defaults' => [ + 'exceptions' => false + ] + ]); - $rules = array( - 'ldaptest_user' => 'required', - 'ldaptest_password' => 'required' - ); - - $validator = Validator::make($request->all(), $rules); - if ($validator->fails()) { - \Log::debug('LDAP Validation test failed.'); - $validation_errors = implode(' ',$validator->errors()->all()); - return response()->json(['message' => $validator->errors()->all()], 400); - } - - - \Log::debug('Preparing to test LDAP login'); - try { - $connection = Ldap::connectToLdap(); - try { - Ldap::bindAdminToLdap($connection); - \Log::debug('Attempting to bind to LDAP for LDAP test'); - try { - $ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password')); - if ($ldap_user) { - \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' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400); - - } catch (\Exception $e) { - \Log::debug('LDAP login failed'); - return response()->json(['message' => $e->getMessage()], 400); - } - - } catch (\Exception $e) { - \Log::debug('Bind failed'); - return response()->json(['message' => $e->getMessage()], 400); - //return response()->json(['message' => $e->getMessage()], 500); - } - } catch (\Exception $e) { - \Log::debug('Connection failed'); - return response()->json(['message' => $e->getMessage()], 500); - } - - - } - - - public function slacktest() - { - - if ($settings = Setting::getSettings()->slack_channel=='') { - \Log::debug('Slack is not enabled. Cannot test.'); - return response()->json(['message' => 'Slack is not enabled, cannot test.'], 400); - } - - \Log::debug('Preparing to test slack connection'); + $payload = json_encode( + [ + 'channel' => e($request->input('slack_channel')), + 'text' => trans('general.slack_test_msg'), + 'username' => e($request->input('slack_botname')), + 'icon_emoji' => ':heart:' + ]); try { - Notification::send($settings = Setting::getSettings(), new SlackTest()); + $slack->post($request->input('slack_endpoint'),['body' => $payload]); return response()->json(['message' => 'Success'], 200); } catch (\Exception $e) { - \Log::debug('Slack connection failed'); - return response()->json(['message' => $e->getMessage()], 400); + return response()->json(['message' => 'Oops! Please check the channel name and webhook endpoint URL. Slack responded with: '.$e->getMessage()], 400); } + return response()->json(['message' => 'Something went wrong :( '], 400); } @@ -143,6 +143,30 @@ class SettingsController extends Controller } + /** + * Get a list of login attempts + * + * @author [A. Gianotto] [] + * @since [v5.0.0] + * @param \Illuminate\Http\Request $request + * @return array + */ + public function showLoginAttempts(Request $request) + { + $allowed_columns = ['id', 'username', 'remote_ip', 'user_agent','successful','created_at']; + + $login_attempts = DB::table('login_attempts'); + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + $sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'created_at'; + + $total = $login_attempts->count(); + $login_attempts->orderBy($sort, $order); + $login_attempt_results = $login_attempts->skip(request('offset', 0))->take(request('limit', 20))->get(); + + return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total); + + } + } diff --git a/app/Http/Controllers/Api/StatuslabelsController.php b/app/Http/Controllers/Api/StatuslabelsController.php index 8a5b55f4c1..22283be8a6 100644 --- a/app/Http/Controllers/Api/StatuslabelsController.php +++ b/app/Http/Controllers/Api/StatuslabelsController.php @@ -2,13 +2,13 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Statuslabel; -use App\Models\Asset; -use App\Http\Transformers\StatuslabelsTransformer; +use App\Http\Controllers\Controller; use App\Http\Transformers\AssetsTransformer; +use App\Http\Transformers\StatuslabelsTransformer; +use App\Models\Asset; +use App\Models\Statuslabel; +use Illuminate\Http\Request; class StatuslabelsController extends Controller { @@ -213,7 +213,7 @@ class StatuslabelsController extends Controller $allowed_columns = [ 'id', - 'name' + 'name', ]; $offset = request('offset', 0); @@ -243,8 +243,6 @@ class StatuslabelsController extends Controller */ public function checkIfDeployable($id) { $statuslabel = Statuslabel::findOrFail($id); - $this->authorize('view', Asset::class); - if ($statuslabel->getStatuslabelType()=='deployable') { return '1'; } diff --git a/app/Http/Controllers/Api/SuppliersController.php b/app/Http/Controllers/Api/SuppliersController.php index a739497944..5616913ff3 100644 --- a/app/Http/Controllers/Api/SuppliersController.php +++ b/app/Http/Controllers/Api/SuppliersController.php @@ -2,13 +2,13 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; use App\Helpers\Helper; -use App\Models\Supplier; -use App\Http\Transformers\SuppliersTransformer; +use App\Http\Controllers\Controller; use App\Http\Transformers\SelectlistTransformer; - +use App\Http\Transformers\SuppliersTransformer; +use App\Models\Supplier; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class SuppliersController extends Controller { @@ -22,7 +22,7 @@ class SuppliersController extends Controller public function index(Request $request) { $this->authorize('view', Supplier::class); - $allowed_columns = ['id','name','address','phone','contact','fax','email','image','assets_count','licenses_count', 'accessories_count']; + $allowed_columns = ['id','name','address','phone','contact','fax','email','image','assets_count','licenses_count', 'accessories_count','url']; $suppliers = Supplier::select( array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image','notes') @@ -169,7 +169,7 @@ class SuppliersController extends Controller // they may not have a ->name value but we want to display something anyway foreach ($suppliers as $supplier) { $supplier->use_text = $supplier->name; - $supplier->use_image = ($supplier->image) ? url('/').'/uploads/suppliers/'.$supplier->image : null; + $supplier->use_image = ($supplier->image) ? Storage::disk('public')->url('suppliers/'.$supplier->image, $supplier->image) : null; } return (new SelectlistTransformer)->transformSelectlist($suppliers); diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 0c735661eb..a130eaa1db 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -2,19 +2,21 @@ namespace App\Http\Controllers\Api; -use Illuminate\Http\Request; -use App\Http\Controllers\Controller; -use App\Http\Transformers\UsersTransformer; -use App\Models\Company; -use App\Models\User; use App\Helpers\Helper; +use App\Http\Controllers\Controller; use App\Http\Requests\SaveUserRequest; -use App\Models\Asset; -use App\Http\Transformers\AssetsTransformer; -use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\AccessoriesTransformer; +use App\Http\Transformers\AssetsTransformer; use App\Http\Transformers\LicensesTransformer; +use App\Http\Transformers\SelectlistTransformer; +use App\Http\Transformers\UsersTransformer; +use App\Models\Asset; +use App\Models\Company; +use App\Models\License; +use App\Models\User; use Auth; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class UsersController extends Controller { @@ -97,6 +99,7 @@ class UsersController extends Controller } $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + $offset = (($users) && (request('offset') > $users->count())) ? 0 : request('offset', 0); // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. @@ -230,6 +233,7 @@ class UsersController extends Controller $tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20); $user->password = bcrypt($request->get('password', $tmp_pass)); + if ($user->save()) { if ($request->filled('groups')) { $user->groups()->sync($request->input('groups')); @@ -271,6 +275,16 @@ class UsersController extends Controller $this->authorize('update', User::class); $user = User::findOrFail($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'))) { + return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.')); + } + + $user->fill($request->all()); if ($user->id == $request->input('manager_id')) { @@ -356,8 +370,16 @@ class UsersController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.')); } - if ($user->delete()) { + + // 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('error', null, trans('admin/users/message.error.delete'))); @@ -414,6 +436,8 @@ class UsersController extends Controller } /** + + * Reset the user's two-factor status * * @author [A. Gianotto] [] diff --git a/app/Http/Controllers/AssetMaintenancesController.php b/app/Http/Controllers/AssetMaintenancesController.php index 9e58aada72..b3f8482f1b 100644 --- a/app/Http/Controllers/AssetMaintenancesController.php +++ b/app/Http/Controllers/AssetMaintenancesController.php @@ -1,26 +1,17 @@ asset) { return redirect()->route('maintenances.index') ->with('error', 'The asset associated with this maintenance does not exist.'); + } elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) { return static::getInsufficientPermissionsRedirect(); } diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index 536a951660..29914b40a2 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -1,23 +1,15 @@ ] - * @since [v1.0] - * @return View - */ + * Returns a view that invokes the ajax tables which actually contains + * the content for the accessories listing, which is generated in getDatatable. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function index() { $this->authorize('index', AssetModel::class); @@ -45,29 +38,31 @@ class AssetModelsController extends Controller } /** - * Returns a view containing the asset model creation form. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return View - */ + * Returns a view containing the asset model creation form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function create() { $this->authorize('create', AssetModel::class); - $category_type = 'asset'; - return view('models/edit')->with('category_type',$category_type) - ->with('depreciation_list', Helper::depreciationList()) - ->with('item', new AssetModel); + return view('models/edit')->with('category_type', 'asset') + ->with('depreciation_list', Helper::depreciationList()) + ->with('item', new AssetModel); } /** - * Validate and process the new Asset Model data. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return Redirect - */ + * Validate and process the new Asset Model data. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param ImageUploadRequest $request + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function store(ImageUploadRequest $request) { @@ -84,13 +79,13 @@ class AssetModelsController extends Controller $model->category_id = $request->input('category_id'); $model->notes = $request->input('notes'); $model->user_id = Auth::id(); - $model->requestable = Input::has('requestable'); + $model->requestable = Request::has('requestable'); if ($request->input('custom_fieldset')!='') { $model->fieldset_id = e($request->input('custom_fieldset')); } - $model = $request->handleImages($model,600, public_path().'/uploads/models'); + $model = $request->handleImages($model); // Was it created? if ($model->save()) { @@ -105,13 +100,14 @@ class AssetModelsController extends Controller } /** - * Returns a view containing the asset model edit form. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $modelId - * @return View - */ + * Returns a view containing the asset model edit form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $modelId + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function edit($modelId = null) { $this->authorize('update', AssetModel::class); @@ -128,14 +124,16 @@ class AssetModelsController extends Controller /** - * Validates and processes form data from the edit - * Asset Model form based on the model ID passed. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $modelId - * @return Redirect - */ + * Validates and processes form data from the edit + * Asset Model form based on the model ID passed. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param ImageUploadRequest $request + * @param int $modelId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function update(ImageUploadRequest $request, $modelId = null) { $this->authorize('update', AssetModel::class); @@ -145,6 +143,8 @@ class AssetModelsController extends Controller return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist')); } + $model = $request->handleImages($model); + $model->depreciation_id = $request->input('depreciation_id'); $model->eol = $request->input('eol'); $model->name = $request->input('name'); @@ -154,6 +154,8 @@ class AssetModelsController extends Controller $model->notes = $request->input('notes'); $model->requestable = $request->input('requestable', '0'); + + $this->removeCustomFieldsDefaultValues($model); if ($request->input('custom_fieldset')=='') { @@ -166,7 +168,6 @@ class AssetModelsController extends Controller } } - $model = $request->handleImages($model,600, public_path().'/uploads/models'); if ($model->save()) { return redirect()->route("models.index")->with('success', trans('admin/models/message.update.success')); @@ -175,14 +176,15 @@ class AssetModelsController extends Controller } /** - * Validate and delete the given Asset Model. An Asset Model - * cannot be deleted if there are associated assets. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $modelId - * @return Redirect - */ + * Validate and delete the given Asset Model. An Asset Model + * cannot be deleted if there are associated assets. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $modelId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function destroy($modelId) { $this->authorize('delete', AssetModel::class); @@ -198,7 +200,7 @@ class AssetModelsController extends Controller if ($model->image) { try { - unlink(public_path().'/uploads/models/'.$model->image); + Storage::disk('public')->delete('models/'.$model->image); } catch (\Exception $e) { \Log::info($e); } @@ -213,13 +215,14 @@ class AssetModelsController extends Controller /** - * Restore a given Asset Model (mark as un-deleted) - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $modelId - * @return Redirect - */ + * Restore a given Asset Model (mark as un-deleted) + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $modelId + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function getRestore($modelId = null) { $this->authorize('create', AssetModel::class); @@ -227,16 +230,8 @@ class AssetModelsController extends Controller $model = AssetModel::withTrashed()->find($modelId); if (isset($model->id)) { - - // Restore the model $model->restore(); - - // Prepare the success message - $success = trans('admin/models/message.restore.success'); - - // Redirect back - return redirect()->route('models.index')->with('success', $success); - + return redirect()->route('models.index')->with('success', trans('admin/models/message.restore.success')); } return redirect()->back()->with('error', trans('admin/models/message.not_found')); @@ -244,13 +239,14 @@ class AssetModelsController extends Controller /** - * Get the model information to present to the model view page - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $modelId - * @return View - */ + * Get the model information to present to the model view page + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $modelId + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function show($modelId = null) { $this->authorize('view', AssetModel::class); @@ -282,12 +278,10 @@ class AssetModelsController extends Controller $model->id = null; // Show the page - $view = View::make('models/edit'); - $view->with('depreciation_list', Helper::depreciationList()); - $view->with('item', $model); - $view->with('clone_model', $model_to_clone); - return $view; - + return view('models/edit') + ->with('depreciation_list', Helper::depreciationList()) + ->with('item', $model) + ->with('clone_model', $model_to_clone); } @@ -301,8 +295,7 @@ class AssetModelsController extends Controller */ public function getCustomFields($modelId) { - $model = AssetModel::find($modelId); - return view("models.custom_fields_form")->with("model", $model); + return view("models.custom_fields_form")->with("model", AssetModel::find($modelId)); } @@ -318,7 +311,7 @@ class AssetModelsController extends Controller public function postBulkEdit(Request $request) { - $models_raw_array = Input::get('ids'); + $models_raw_array = $request->input('ids'); // Make sure some IDs have been selected if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) { @@ -367,7 +360,7 @@ class AssetModelsController extends Controller public function postBulkEditSave(Request $request) { - $models_raw_array = Input::get('ids'); + $models_raw_array = $request->input('ids'); $update_array = array(); @@ -408,7 +401,7 @@ class AssetModelsController extends Controller */ public function postBulkDelete(Request $request) { - $models_raw_array = Input::get('ids'); + $models_raw_array = $request->input('ids'); if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) { diff --git a/app/Http/Controllers/AssetCheckinController.php b/app/Http/Controllers/Assets/AssetCheckinController.php similarity index 73% rename from app/Http/Controllers/AssetCheckinController.php rename to app/Http/Controllers/Assets/AssetCheckinController.php index 354636b41e..4c0ac970a7 100644 --- a/app/Http/Controllers/AssetCheckinController.php +++ b/app/Http/Controllers/Assets/AssetCheckinController.php @@ -1,25 +1,29 @@ ] - * @param int $assetId - * @param string $backto - * @since [v1.0] - * @return View - */ + * Returns a view that presents a form to check an asset back into inventory. + * + * @author [A. Gianotto] [] + * @param int $assetId + * @param string $backto + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v1.0] + */ public function create($assetId, $backto = null) { // Check if the asset exists @@ -40,6 +44,7 @@ class AssetCheckinController extends Controller * @param int $assetId * @param null $backto * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException * @since [v1.0] */ public function store(AssetCheckinRequest $request, $assetId = null, $backto = null) @@ -50,14 +55,14 @@ class AssetCheckinController extends Controller return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist')); } + if (is_null($target = $asset->assignedTo)) { + return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in')); + } $this->authorize('checkin', $asset); if ($asset->assignedType() == Asset::USER) { $user = $asset->assignedTo; } - if (is_null($target = $asset->assignedTo)) { - return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in')); - } $asset->expected_checkin = null; $asset->last_checkout = null; @@ -77,21 +82,14 @@ class AssetCheckinController extends Controller $asset->location_id = e($request->get('location_id')); } + $checkin_at = date('Y-m-d'); + if($request->filled('checkin_at')){ + $checkin_at = $request->input('checkin_at'); + } + // Was the asset updated? if ($asset->save()) { - $logaction = $asset->logCheckin($target, e(request('note'))); - - $data['log_id'] = $logaction->id; - $data['first_name'] = get_class($target) == User::class ? $target->first_name : ''; - $data['last_name'] = get_class($target) == User::class ? $target->last_name : ''; - $data['item_name'] = $asset->present()->name(); - $data['checkin_date'] = $logaction->created_at; - $data['item_tag'] = $asset->asset_tag; - $data['item_serial'] = $asset->serial; - $data['note'] = $logaction->note; - $data['manufacturer_name'] = $asset->model->manufacturer->name; - $data['model_name'] = $asset->model->name; - $data['model_number'] = $asset->model->model_number; + event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at)); if ((isset($user)) && ($backto =='user')) { return redirect()->route("users.show", $user->id)->with('success', trans('admin/hardware/message.checkin.success')); diff --git a/app/Http/Controllers/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php similarity index 92% rename from app/Http/Controllers/AssetCheckoutController.php rename to app/Http/Controllers/Assets/AssetCheckoutController.php index 1a8f11d467..5671395982 100644 --- a/app/Http/Controllers/AssetCheckoutController.php +++ b/app/Http/Controllers/Assets/AssetCheckoutController.php @@ -1,15 +1,14 @@ determineCheckoutTarget($asset); - if ($asset->is($target)) { - throw new CheckoutNotAllowed('You cannot check an asset out to itself.'); - } + $asset = $this->updateAssetLocation($asset, $target); $checkout_at = date("Y-m-d H:i:s"); diff --git a/app/Http/Controllers/AssetFilesController.php b/app/Http/Controllers/Assets/AssetFilesController.php similarity index 59% rename from app/Http/Controllers/AssetFilesController.php rename to app/Http/Controllers/Assets/AssetFilesController.php index 4ce67fc84a..cbf15219b7 100644 --- a/app/Http/Controllers/AssetFilesController.php +++ b/app/Http/Controllers/Assets/AssetFilesController.php @@ -1,13 +1,14 @@ authorize('update', $asset); - $destinationPath = config('app.private_uploads').'/assets'; - if ($request->hasFile('file')) { + + if (!Storage::exists('private_uploads/assets')) Storage::makeDirectory('private_uploads/assets', 775); + foreach ($request->file('file') as $file) { $extension = $file->getClientOriginalExtension(); - $filename = 'hardware-'.$asset->id.'-'.str_random(8); - $filename .= '-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - $file->move($destinationPath, $filename); - $asset->logUpload($filename, e($request->get('notes'))); + $file_name = 'hardware-'.$asset->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; + Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file)); + $asset->logUpload($file_name, e($request->get('notes'))); } return redirect()->back()->with('success', trans('admin/hardware/message.upload.success')); } @@ -45,14 +47,15 @@ class AssetFilesController extends Controller } /** - * Check for permissions and display the file. - * - * @author [A. Gianotto] [] - * @param int $assetId - * @param int $fileId - * @since [v1.0] - * @return View - */ + * Check for permissions and display the file. + * + * @author [A. Gianotto] [] + * @param int $assetId + * @param int $fileId + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function show($assetId = null, $fileId = null, $download = true) { $asset = Asset::find($assetId); @@ -65,24 +68,25 @@ class AssetFilesController extends Controller ->header('Content-Type', 'text/plain'); } - $file = $log->get_src('assets'); + $file = 'private_uploads/assets/'.$log->filename; + \Log::debug('Checking for '.$file); if ($log->action_type =='audit') { - $file = $log->get_src('audits'); + $file = 'private_uploads/audits/'.$log->filename; } - if (!file_exists($file)) { + if (!Storage::exists($file)) { return response('File '.$file.' not found on server', 404) ->header('Content-Type', 'text/plain'); } if ($download != 'true') { - if ($contents = file_get_contents($file)) { - return Response::make($contents)->header('Content-Type', mime_content_type($file)); + if ($contents = file_get_contents(Storage::url($file))) { + return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file))); } return JsonResponse::create(["error" => "Failed validation: "], 500); } - return Response::download($file); + return Storage::download($file); } // Prepare the error message $error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]); @@ -92,35 +96,35 @@ class AssetFilesController extends Controller } /** - * Delete the associated file - * - * @author [A. Gianotto] [] - * @param int $assetId - * @param int $fileId - * @since [v1.0] - * @return View - */ + * Delete the associated file + * + * @author [A. Gianotto] [] + * @param int $assetId + * @param int $fileId + * @since [v1.0] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function destroy($assetId = null, $fileId = null) { $asset = Asset::find($assetId); $this->authorize('update', $asset); - $destinationPath = config('app.private_uploads').'/imports/assets'; + $rel_path = 'storage/private_uploads/assets'; // the asset is valid if (isset($asset->id)) { $this->authorize('update', $asset); - $log = Actionlog::find($fileId); if ($log) { - $full_filename = $destinationPath.'/'.$log->filename; - if (file_exists($full_filename)) { - unlink($destinationPath.'/'.$log->filename); + if (file_exists(base_path().'/'.$rel_path.'/'.$log->filename)) { + Storage::disk('public')->delete($rel_path.'/'.$log->filename); } $log->delete(); return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success')); } - return redirect()->back()->with('error', 'Could not find matching upload log.'); - + $log->delete(); + return redirect()->back() + ->with('success', trans('admin/hardware/message.deletefile.success')); } // Redirect to the hardware management page diff --git a/app/Http/Controllers/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php similarity index 69% rename from app/Http/Controllers/AssetsController.php rename to app/Http/Controllers/Assets/AssetsController.php index f7d8603d90..2a31d75ca8 100755 --- a/app/Http/Controllers/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -1,44 +1,34 @@ ] * @see AssetController::getDatatable() method that generates the JSON response * @since [v1.0] + * @param Request $request * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index(Request $request) { $this->authorize('index', Asset::class); - if ($request->filled('company_id')) { - $company = Company::find($request->input('company_id')); - } else { - $company = null; - } + $company = Company::find($request->input('company_id')); return view('hardware/index')->with('company', $company); } @@ -110,117 +98,114 @@ class AssetsController extends Controller * @since [v1.0] * @return Redirect */ - public function store(AssetRequest $request) + public function store(ImageUploadRequest $request) { $this->authorize(Asset::class); + // Handle asset tags - there could be one, or potentially many. + // This is only necessary on create, not update, since bulk editing is handled + // differently + $asset_tags = $request->input('asset_tags'); - $asset = new Asset(); - $asset->model()->associate(AssetModel::find($request->input('model_id'))); + $settings = Setting::getSettings(); - $asset->name = $request->input('name'); - $asset->serial = $request->input('serial'); - $asset->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $asset->model_id = $request->input('model_id'); - $asset->order_number = $request->input('order_number'); - $asset->notes = $request->input('notes'); - $asset->asset_tag = $request->input('asset_tag'); - $asset->user_id = Auth::id(); - $asset->archived = '0'; - $asset->physical = '1'; - $asset->depreciate = '0'; - $asset->status_id = request('status_id', 0); - $asset->warranty_months = request('warranty_months', null); - $asset->purchase_cost = Helper::ParseFloat($request->get('purchase_cost')); - $asset->purchase_date = request('purchase_date', null); - $asset->assigned_to = request('assigned_to', null); - $asset->supplier_id = request('supplier_id', 0); - $asset->requestable = request('requestable', 0); - $asset->rtd_location_id = request('rtd_location_id', null); - + $success = false; + $serials = $request->input('serials'); - if ($asset->assigned_to=='') { - $asset->location_id = $request->input('rtd_location_id', null); - } + for ($a = 1; $a <= count($asset_tags); $a++) { - // Create the image (if one was chosen.) - if ($request->filled('image')) { - $image = $request->input('image'); + $asset = new Asset(); + $asset->model()->associate(AssetModel::find($request->input('model_id'))); + $asset->name = $request->input('name'); - // After modification, the image is prefixed by mime info like the following: - // data:image/jpeg;base64,; This causes the image library to be unhappy, so we need to remove it. - $header = explode(';', $image, 2)[0]; - // Grab the image type from the header while we're at it. - $extension = substr($header, strpos($header, '/')+1); - // Start reading the image after the first comma, postceding the base64. - $image = substr($image, strpos($image, ',')+1); - - $file_name = str_random(25).".".$extension; - - $directory= public_path('uploads/assets/'); - // Check if the uploads directory exists. If not, try to create it. - if (!file_exists($directory)) { - mkdir($directory, 0755, true); + // Check for a corresponding serial + if (($serials) && (array_key_exists($a, $serials))) { + $asset->serial = $serials[$a]; } - $path = public_path('uploads/assets/'.$file_name); - try { - Image::make($image)->resize(800, 800, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path); - $asset->image = $file_name; - } catch (\Exception $e) { - \Input::flash(); - $messageBag = new \Illuminate\Support\MessageBag(); - $messageBag->add('image', $e->getMessage()); - \Session()->flash('errors', \Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', $messageBag)); - return response()->json(['image' => $e->getMessage()], 422); + + if (($asset_tags) && (array_key_exists($a, $asset_tags))) { + $asset->asset_tag = $asset_tags[$a]; } - } + $asset->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $asset->model_id = $request->input('model_id'); + $asset->order_number = $request->input('order_number'); + $asset->notes = $request->input('notes'); + $asset->user_id = Auth::id(); + $asset->archived = '0'; + $asset->physical = '1'; + $asset->depreciate = '0'; + $asset->status_id = request('status_id', 0); + $asset->warranty_months = request('warranty_months', null); + $asset->purchase_cost = Helper::ParseFloat($request->get('purchase_cost')); + $asset->purchase_date = request('purchase_date', null); + $asset->assigned_to = request('assigned_to', null); + $asset->supplier_id = request('supplier_id', 0); + $asset->requestable = request('requestable', 0); + $asset->rtd_location_id = request('rtd_location_id', null); - // Update custom fields in the database. - // Validation for these fields is handled through the AssetRequest form request - $model = AssetModel::find($request->get('model_id')); + if (!empty($settings->audit_interval)) { + $asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString(); + } - if (($model) && ($model->fieldset)) { - foreach ($model->fieldset->fields as $field) { - if ($field->field_encrypted=='1') { - if (Gate::allows('admin')) { - $asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug())); + if ($asset->assigned_to=='') { + $asset->location_id = $request->input('rtd_location_id', null); + } + + // Create the image (if one was chosen.) + if ($request->has('image')) { + $asset = $request->handleImages($asset); + } + + // Update custom fields in the database. + // Validation for these fields is handled through the AssetRequest form request + $model = AssetModel::find($request->get('model_id')); + + if (($model) && ($model->fieldset)) { + foreach ($model->fieldset->fields as $field) { + if ($field->field_encrypted=='1') { + if (Gate::allows('admin')) { + $asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug())); + } + } else { + $asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug()); } - } else { - $asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug()); } } + + // Validate the asset before saving + if ($asset->isValid() && $asset->save()) { + + if (request('assigned_user')) { + $target = User::find(request('assigned_user')); + $location = $target->location_id; + } elseif (request('assigned_asset')) { + $target = Asset::find(request('assigned_asset')); + $location = $target->location_id; + } elseif (request('assigned_location')) { + $target = Location::find(request('assigned_location')); + $location = $target->id; + } + + 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', e($request->get('name')), $location); + } + + $success = true; + + + } + } - // Was the asset created? - if ($asset->save()) { - - - if (request('assigned_user')) { - $target = User::find(request('assigned_user')); - $location = $target->location_id; - } elseif (request('assigned_asset')) { - $target = Asset::find(request('assigned_asset')); - $location = $target->location_id; - } elseif (request('assigned_location')) { - $target = Location::find(request('assigned_location')); - $location = $target->id; - } - - if (isset($target)) { - $asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')), $location); - } + if ($success) { // Redirect to the asset listing page - \Session::flash('success', trans('admin/hardware/message.create.success')); - return response()->json(['redirect_url' => route('hardware.index')]); + return redirect()->route('hardware.index') + ->with('success', trans('admin/hardware/message.create.success')); } - \Input::flash(); - \Session::flash('errors', $asset->getErrors()); - return response()->json(['errors' => $asset->getErrors()], 500); + + return redirect()->back()->withInput()->withErrors($asset->getErrors()); + } /** @@ -298,7 +283,7 @@ class AssetsController extends Controller * @return Redirect */ - public function update(AssetRequest $request, $assetId = null) + public function update(ImageUploadRequest $request, $assetId = null) { // Check if the asset exists if (!$asset = Asset::find($assetId)) { @@ -312,6 +297,7 @@ class AssetsController extends Controller $asset->purchase_cost = Helper::ParseFloat($request->input('purchase_cost', null)); $asset->purchase_date = $request->input('purchase_date', null); $asset->supplier_id = $request->input('supplier_id', null); + $asset->expected_checkin = $request->input('expected_checkin', null); // If the box isn't checked, it's not in the request at all. $asset->requestable = $request->filled('requestable'); @@ -327,54 +313,25 @@ class AssetsController extends Controller unlink(public_path().'/uploads/assets/'.$asset->image); $asset->image = ''; } catch (\Exception $e) { - \Log::debug($e); + \Log::info($e); } } // Update the asset data + $asset_tag = $request->input('asset_tags'); + $serial = $request->input('serials'); $asset->name = $request->input('name'); - $asset->serial = $request->input('serial'); + $asset->serial = $serial[1]; $asset->company_id = Company::getIdForCurrentUser($request->input('company_id')); $asset->model_id = $request->input('model_id'); $asset->order_number = $request->input('order_number'); - $asset->asset_tag = $request->input('asset_tag'); + $asset->asset_tag = $asset_tag[1]; $asset->notes = $request->input('notes'); $asset->physical = '1'; - // Update the image - if ($request->filled('image')) { - $image = $request->input('image'); - // See postCreate for more explaination of the following. - $header = explode(';', $image, 2)[0]; - $extension = substr($header, strpos($header, '/')+1); - $image = substr($image, strpos($image, ',')+1); - - $directory= public_path('uploads/assets/'); - // Check if the uploads directory exists. If not, try to create it. - if (!file_exists($directory)) { - mkdir($directory, 0755, true); - } - - $file_name = str_random(25).".".$extension; - $path = public_path('uploads/assets/'.$file_name); - try { - Image::make($image)->resize(800, 800, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path); - $asset->image = $file_name; - } catch (\Exception $e) { - \Input::flash(); - $messageBag = new \Illuminate\Support\MessageBag(); - $messageBag->add('image', $e->getMessage()); - \Session()->flash('errors', \Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', $messageBag)); - return response()->json(['image' => $e->getMessage()], 422); - } - $asset->image = $file_name; - } + $asset = $request->handleImages($asset); // Update custom fields in the database. // Validation for these fields is handlded through the AssetRequest form request @@ -395,19 +352,11 @@ class AssetsController extends Controller if ($asset->save()) { - - // Update any assigned assets with the new location_id from the parent asset - - Asset::where('assigned_type', '\\App\\Models\\Asset')->where('assigned_to', $asset->id) - ->update(['location_id' => $asset->location_id]); - - // Redirect to the new asset page - \Session::flash('success', trans('admin/hardware/message.update.success')); - return response()->json(['redirect_url' => route("hardware.show", $assetId)]); + return redirect()->route("hardware.show", $assetId) + ->with('success', trans('admin/hardware/message.update.success')); } - \Input::flash(); - \Session::flash('errors', $asset->getErrors()); - return response()->json(['errors' => $asset->getErrors()], 500); + + return redirect()->back()->withInput()->withErrors($asset->getErrors()); } /** @@ -432,6 +381,14 @@ class AssetsController extends Controller ->where('id', $asset->id) ->update(array('assigned_to' => null)); + if ($asset->image) { + try { + Storage::disk('public')->delete('assets'.'/'.$asset->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + $asset->delete(); return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success')); @@ -440,63 +397,22 @@ class AssetsController extends Controller /** - * Searches the assets table by tag, and redirects if it finds one. - * - * This is used by the top search box in Snipe-IT, but as of 4.9.x - * can also be used as a url segment. - * - * https://yoursnipe.com/hardware/bytag/?assetTag=foo - * - * OR - * - * https://yoursnipe.com/hardware/bytag/foo - * - * The latter is useful if you're doing home-grown barcodes, or - * some other automation where you don't always know the internal ID of - * an asset and don't want to query for it. + * Searches the assets table by asset tag, and redirects if it finds one * * @author [A. Gianotto] [] - * @param string $tag * @since [v3.0] * @return Redirect */ - public function getAssetByTag(Request $request, $tag = null) + public function getAssetByTag(Request $request) { - $topsearch = ($request->get('topsearch')=="true"); - // We need this part to determine whether a url query parameter has been passed, OR - // whether it's the url fragment we need to look at - $tag = ($request->get('assetTag')) ? $request->get('assetTag') : $tag; - - if (!$asset = Asset::where('asset_tag', '=', $tag)->first()) { + if (!$asset = Asset::where('asset_tag', '=', $request->get('assetTag'))->first()) { return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist')); } $this->authorize('view', $asset); return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch); } - - - /** - * Searches the assets table by serial, and redirects if it finds one - * - * @author [A. Gianotto] [] - * @param string $serial - * @since [v4.9.1] - * @return Redirect - */ - public function getAssetBySerial(Request $request, $serial = null) - { - - $serial = ($request->get('serial')) ? $request->get('serial') : $serial; - if (!$asset = Asset::where('serial', '=', $serial)->first()) { - return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist')); - } - $this->authorize('view', $asset); - return redirect()->route('hardware.show', $asset->id); - } - - /** * Return a QR code for the asset * @@ -547,7 +463,6 @@ class AssetsController extends Controller $barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png'; if (isset($asset->id, $asset->asset_tag)) { - if (file_exists($barcode_file)) { $header = ['Content-type' => 'image/png']; return response()->file($barcode_file, $header); @@ -556,26 +471,37 @@ class AssetsController extends Controller $barcode_width = ($settings->labels_width - $settings->labels_display_sgutter) * 96.000000000001; $barcode = new \Com\Tecnick\Barcode\Barcode(); + $barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode,$asset->asset_tag,($barcode_width < 300 ? $barcode_width : 300),50); - try { - - $barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode,$asset->asset_tag,($barcode_width < 300 ? $barcode_width : 300),50); - - file_put_contents($barcode_file, $barcode_obj->getPngData()); - return response($barcode_obj->getPngData())->header('Content-type', 'image/png'); - - } catch (\Exception $e) { - \Log::debug('Error creating barcode: '.$e->getMessage()); - \Log::debug('This usually happens because the asset tags are of a format that is not compatible with the selected barcode type.'); - $img = file_get_contents(public_path().'/uploads/barcodes/invalid_barcode.gif'); - return response($img)->header('Content-type', 'image/gif'); - } - - + file_put_contents($barcode_file, $barcode_obj->getPngData()); + return response($barcode_obj->getPngData())->header('Content-type', 'image/png'); } } } + + /** + * Return a label for an individual asset. + * + * @author [L. Swartzendruber] [ + * @param int $assetId + * @return View + */ + public function getLabel($assetId = null) + { + if (isset($assetId)) { + $asset = Asset::find($assetId); + $this->authorize('view', $asset); + + return view('hardware/labels') + ->with('assets', Asset::find($asset)) + ->with('settings', Setting::getSettings()) + ->with('bulkedit', false) + ->with('count', 0); + } + } + + /** * Returns a view that presents a form to clone an asset. * @@ -615,7 +541,7 @@ class AssetsController extends Controller */ public function getImportHistory() { - $this->authorize('checkout', Asset::class); + $this->authorize('admin'); return view('hardware/history'); } @@ -639,16 +565,13 @@ class AssetsController extends Controller if (!ini_get("auto_detect_line_endings")) { ini_set("auto_detect_line_endings", '1'); } - - $csv = Reader::createFromPath(Input::file('user_import_csv')); + $csv = Reader::createFromPath($request->file('user_import_csv')); $csv->setHeaderOffset(0); $results = $csv->getRecords(); $item = array(); $status = array(); $status['error'] = array(); $status['success'] = array(); - - foreach ($results as $row) { if (is_array($row)) { $row = array_change_key_case($row, CASE_LOWER); @@ -657,29 +580,23 @@ class AssetsController extends Controller $item[$asset_tag] = array(); } $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']); - $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"); - if ($asset = Asset::where('asset_tag', '=', $asset_tag)->first()) { $item[$asset_tag][$batch_counter]['asset_id'] = $asset->id; - $base_username = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $item[$asset_tag][$batch_counter]['name']); $user = User::where('username', '=', $base_username['username']); $user_query = ' on username '.$base_username['username']; - if ($request->input('match_firstnamelastname')=='1') { $firstnamedotlastname = User::generateFormattedNameFromFullName('firstname.lastname', $item[$asset_tag][$batch_counter]['name']); $item[$asset_tag][$batch_counter]['username'][] = $firstnamedotlastname['username']; $user->orWhere('username', '=', $firstnamedotlastname['username']); $user_query .= ', or on username '.$firstnamedotlastname['username']; } - if ($request->input('match_flastname')=='1') { $flastname = User::generateFormattedNameFromFullName('filastname', $item[$asset_tag][$batch_counter]['name']); $item[$asset_tag][$batch_counter]['username'][] = $flastname['username']; @@ -699,12 +616,10 @@ class AssetsController extends Controller $user_query .= ', or on username '.$user_email; } } - // A matching user was found if ($user = $user->first()) { $item[$asset_tag][$batch_counter]['checkedout_to'] = $user->id; $item[$asset_tag][$batch_counter]['user_id'] = $user->id; - Actionlog::firstOrCreate(array( 'item_id' => $asset->id, 'item_type' => Asset::class, @@ -715,9 +630,7 @@ class AssetsController extends Controller 'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'], 'action_type' => 'checkout', )); - $asset->assigned_to = $user->id; - 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 { @@ -733,19 +646,16 @@ 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( @@ -764,6 +674,11 @@ class AssetsController extends Controller return view('hardware/history')->with('status', $status); } + public function sortByName(array $recordA, array $recordB): int + { + return strcmp($recordB['Full Name'], $recordA['Full Name']); + } + /** * Retore a deleted asset. * @@ -824,7 +739,7 @@ class AssetsController extends Controller } - public function auditStore(AssetFileRequest $request, $id) + public function auditStore(Request $request, $id) { $this->authorize('audit', Asset::class); @@ -847,24 +762,28 @@ class AssetsController extends Controller $asset->next_audit_date = $request->input('next_audit_date'); $asset->last_audit_date = date('Y-m-d h:i:s'); + // Check to see if they checked the box to update the physical location, + // not just note it in the audit notes + if ($request->input('update_location')=='1') { + \Log::debug('update location in audit'); + $asset->location_id = $request->input('location_id'); + } + + if ($asset->save()) { - - - $filename = ''; - + $file_name = ''; + // Upload an image, if attached if ($request->hasFile('image')) { - $file = $request->file('image'); - try { - $destinationPath = config('app.private_uploads').'/audits'; - $extension = $file->getClientOriginalExtension(); - $filename = 'audit-'.$asset->id.'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - $file->move($destinationPath, $filename); - } catch (\Exception $e) { - \Log::info($e); - } + $path = 'private_uploads/audits'; + 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'), $filename); + + $asset->logAudit($request->input('note'), $request->input('location_id'), $file_name); return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success')); } } diff --git a/app/Http/Controllers/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php similarity index 91% rename from app/Http/Controllers/BulkAssetsController.php rename to app/Http/Controllers/Assets/BulkAssetsController.php index eab7ce0cc7..1a6da89c96 100644 --- a/app/Http/Controllers/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -1,12 +1,12 @@ with('assets', Asset::find($asset_ids)) ->with('settings', Setting::getSettings()) + ->with('bulkedit', true) ->with('count', 0); case 'delete': $assets = Asset::with('assignedTo', 'location')->find($asset_ids); @@ -75,6 +78,7 @@ class BulkAssetsController extends Controller $assets = array_keys($request->input('ids')); if (($request->filled('purchase_date')) + || ($request->filled('expected_checkin')) || ($request->filled('purchase_cost')) || ($request->filled('supplier_id')) || ($request->filled('order_number')) @@ -89,6 +93,7 @@ class BulkAssetsController extends Controller $this->update_array = []; $this->conditionallyAddItem('purchase_date') + ->conditionallyAddItem('expected_checkin') ->conditionallyAddItem('model_id') ->conditionallyAddItem('order_number') ->conditionallyAddItem('requestable') @@ -130,10 +135,11 @@ class BulkAssetsController extends Controller * @var Array */ private $update_array; + /** * Adds parameter to update array for an item if it exists in request - * @param String $field field name - * @return this Model for Chaining + * @param String $field field name + * @return BulkAssetsController Model for Chaining */ protected function conditionallyAddItem($field) { @@ -147,7 +153,9 @@ class BulkAssetsController extends Controller * Save bulk deleted. * * @author [A. Gianotto] [] + * @param Request $request * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException * @internal param array $assets * @since [v2.0] */ @@ -200,9 +208,11 @@ class BulkAssetsController extends Controller $asset_ids = array_filter($request->get('selected_assets')); - foreach ($asset_ids as $asset_id) { - if ($target->id == $asset_id && request('checkout_to_type') =='asset') { - return redirect()->back()->with('error', 'You cannot check an asset out to itself.'); + if(request('checkout_to_type') =='asset') { + foreach ($asset_ids as $asset_id) { + if ($target->id == $asset_id) { + return redirect()->back()->with('error', 'You cannot check an asset out to itself.'); + } } } $checkout_at = date("Y-m-d H:i:s"); diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index a7f3c591ad..6c33c999cd 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -58,7 +58,12 @@ class ForgotPasswordController extends Controller * buffer overflow issues with attackers sending very large * payloads through. */ - $this->validate($request, ['email' => 'required|email|max:250']); + + $request->validate([ + 'email' => ['required', 'email', 'max:255'], + ]); + + /** * If we find a matching email with an activated user, we will @@ -70,12 +75,15 @@ class ForgotPasswordController extends Controller $response = $this->broker()->sendResetLink( array_merge( $request->only('email'), - ['activated' => '1'] + ['activated' => '1'], + ['ldap_import' => '0'] ) ); if ($response === \Password::RESET_LINK_SENT) { - return redirect()->route('login')->with('status', trans($response)); + \Log::info('Password reset attempt: User '.$request->input('email').' found, password reset sent'); + } else { + \Log::info('Password reset attempt: User '.$request->input('email').' not found or user is inactive'); } @@ -92,13 +100,10 @@ class ForgotPasswordController extends Controller * It's bad UX, but better security. The compromises we sometimes have to make. */ - if ($response == 'passwords.user') { - \Log::debug('User with email '.$request->input('email').' attempted a password reset request but was not found. No email was sent.'); - return redirect()->route('login')->with('success', trans('passwords.user_inactive')); + // Regardless of response, we do not want to disclose the status of a user account, + // so we give them a generic "If this exists, we're TOTALLY gonna email you" response + return redirect()->route('login')->with('success',trans('passwords.sent')); } - return back()->withErrors( - ['email' => trans($response)] - ); - } + } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index b9b238167f..3ed9940118 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -2,20 +2,21 @@ namespace App\Http\Controllers\Auth; -use Validator; use App\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\ThrottlesLogins; use App\Models\Setting; -use App\Models\Ldap; use App\Models\User; -use Auth; -use Config; +use App\Services\LdapAd; +use App\Services\Saml; +use Com\Tecnick\Barcode\Barcode; +use Google2FA; +use Illuminate\Foundation\Auth\ThrottlesLogins; use Illuminate\Http\Request; -use Input; -use Redirect; +use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Session; +use Illuminate\Support\Facades\Validator; use Log; -use View; -use PragmaRX\Google2FA\Google2FA; +use Redirect; /** * This controller handles authentication for the user, including local @@ -39,22 +40,43 @@ class LoginController extends Controller */ protected $redirectTo = '/'; + /** + * @var LdapAd + */ + protected $ldap; + + /** + * @var Saml + */ + protected $saml; + /** * Create a new authentication controller instance. * + * @param LdapAd $ldap + * @param Saml $saml + * * @return void */ - public function __construct() + public function __construct(LdapAd $ldap, Saml $saml) { + parent::__construct(); $this->middleware('guest', ['except' => ['logout','postTwoFactorAuth','getTwoFactorAuth','getTwoFactorEnroll']]); - \Session::put('backUrl', \URL::previous()); + Session::put('backUrl', \URL::previous()); + $this->ldap = $ldap; + $this->saml = $saml; } function showLoginForm(Request $request) { $this->loginViaRemoteUser($request); + $this->loginViaSaml($request); if (Auth::check()) { - return redirect()->intended('dashboard'); + return redirect()->intended('/'); + } + + if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == "1" && !($request->has('nosaml') || $request->session()->has('error'))) { + return redirect()->route('saml.login'); } if (Setting::getSettings()->login_common_disabled == "1") { @@ -64,11 +86,76 @@ class LoginController extends Controller return view('auth.login'); } + /** + * Log in a user by SAML + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param Request $request + * + * @return User + * + * @throws \Exception + */ + private function loginViaSaml(Request $request) + { + $saml = $this->saml; + $samlData = $request->session()->get('saml_login'); + if ($saml->isEnabled() && !empty($samlData)) { + try { + LOG::debug("Attempting to log user in by SAML authentication."); + $user = $saml->samlLogin($samlData); + if(!is_null($user)) { + Auth::login($user, true); + } else { + $username = $saml->getUsername(); + LOG::debug("SAML user '$username' could not be found in database."); + $request->session()->flash('error', trans('auth/message.signin.error')); + $saml->clearData(); + } + + if ($user = Auth::user()) { + $user->last_login = \Carbon::now(); + $user->save(); + } + } catch (\Exception $e) { + LOG::debug("There was an error authenticating the SAML user: " . $e->getMessage()); + throw new \Exception($e->getMessage()); + } + } + } + + /** + * Log in a user by LDAP + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param Request $request + * + * @return User + * + * @throws \Exception + */ + private function loginViaLdap(Request $request): User + { + try { + return $this->ldap->ldapLogin($request->input('username'), $request->input('password')); + } catch (\Exception $ex) { + LOG::debug("LDAP user login: " . $ex->getMessage()); + throw new \Exception($ex->getMessage()); + } + } + private function loginViaRemoteUser(Request $request) { - $remote_user = $request->server('REMOTE_USER'); + $header_name = Setting::getSettings()->login_remote_user_header_name ?: 'REMOTE_USER'; + $remote_user = $request->server($header_name); if (Setting::getSettings()->login_remote_user_enabled == "1" && isset($remote_user) && !empty($remote_user)) { - Log::debug("Authenticatiing via REMOTE_USER."); + Log::debug("Authenticating via HTTP header $header_name."); $pos = strpos($remote_user, '\\'); if ($pos > 0) { @@ -85,53 +172,6 @@ class LoginController extends Controller } } - private function loginViaLdap(Request $request) - { - Log::debug("Binding user to LDAP."); - $ldap_user = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password')); - if (!$ldap_user) { - Log::debug("LDAP user ".$request->input('username')." not found in LDAP or could not bind"); - throw new \Exception("Could not find user in LDAP directory"); - } else { - Log::debug("LDAP user ".$request->input('username')." successfully bound to LDAP"); - } - - // Check if the user already exists in the database and was imported via LDAP - $user = User::where('username', '=', Input::get('username'))->whereNull('deleted_at')->where('ldap_import', '=', 1)->where('activated', '=', '1')->first(); - Log::debug("Local auth lookup complete"); - - // The user does not exist in the database. Try to get them from LDAP. - // If user does not exist and authenticates successfully with LDAP we - // will create it on the fly and sign in with default permissions - if (!$user) { - Log::debug("Local user ".Input::get('username')." does not exist"); - Log::debug("Creating local user ".Input::get('username')); - - if ($user = Ldap::createUserFromLdap($ldap_user)) { //this handles passwords on its own - Log::debug("Local user created."); - } else { - Log::debug("Could not create local user."); - throw new \Exception("Could not create local user"); - } - // If the user exists and they were imported from LDAP already - } else { - Log::debug("Local user ".$request->input('username')." exists in database. Updating existing user against LDAP."); - - $ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user); - - if (Setting::getSettings()->ldap_pw_sync=='1') { - $user->password = bcrypt($request->input('password')); - } - - $user->email = $ldap_attr['email']; - $user->first_name = $ldap_attr['firstname']; - $user->last_name = $ldap_attr['lastname']; - $user->save(); - } // End if(!user) - return $user; - } - - /** * Account sign in form processing. * @@ -143,7 +183,7 @@ class LoginController extends Controller return view('errors.403'); } - $validator = $this->validator(Input::all()); + $validator = $this->validator($request->all()); if ($validator->fails()) { return redirect()->back()->withInput()->withErrors($validator); @@ -160,9 +200,10 @@ class LoginController extends Controller $user = null; // Should we even check for LDAP users? - if (Setting::getSettings()->ldap_enabled=='1') { - Log::debug("LDAP is enabled."); + if ($this->ldap->init()) { + LOG::debug("LDAP is enabled."); try { + LOG::debug("Attempting to log user in by LDAP authentication."); $user = $this->loginViaLdap($request); Auth::login($user, true); @@ -227,15 +268,27 @@ class LoginController extends Controller return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.already_enrolled')); } - $google2fa = new Google2FA(); - $secret = $google2fa->generateSecretKey(); + $secret = Google2FA::generateSecretKey(); $user->two_factor_secret = $secret; $user->save(); - $barcode = new \Com\Tecnick\Barcode\Barcode(); - $barcode_obj = $barcode->getBarcodeObj('QRCODE', 'otpauth://totp/'.urlencode($settings->site_name).':'.urlencode($user->username).'?secret='.urlencode($secret).'&issuer=Snipe-IT&period=30', 300, 300, 'black', array(-2, -2, -2, -2)); - return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj); + $barcode = new Barcode(); + $barcode_obj = + $barcode->getBarcodeObj( + 'QRCODE', + sprintf( + 'otpauth://totp/%s:%s?secret=%s&issuer=Snipe-IT&period=30', + urlencode($settings->site_name), + urlencode($user->username), + urlencode($secret) + ), + 300, + 300, + 'black', + [-2, -2, -2, -2] + ); + return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj); } @@ -266,6 +319,8 @@ class LoginController extends Controller /** * Two factor code submission * + * @param Request $request + * * @return Redirect */ public function postTwoFactorAuth(Request $request) @@ -279,11 +334,14 @@ class LoginController extends Controller return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required')); } + if (!$request->has('two_factor_secret')) { + return redirect()->route('two-factor')->with('error', 'Two-factor code is required.'); + } + $user = Auth::user(); - $google2fa = new Google2FA(); $secret = $request->input('two_factor_secret'); - if ($google2fa->verifyKey($user->two_factor_secret, $secret)) { + if (Google2FA::verifyKey($user->two_factor_secret, $secret)) { $user->two_factor_enrolled = 1; $user->save(); $request->session()->put('2fa_authed', 'true'); @@ -299,21 +357,47 @@ class LoginController extends Controller /** * Logout page. * + * @param Request $request + * * @return Redirect */ public function logout(Request $request) { + $settings = Setting::getSettings(); + $saml = $this->saml; + $sloRedirectUrl = null; + $sloRequestUrl = null; + + if ($saml->isEnabled()) { + $auth = $saml->getAuth(); + $sloRedirectUrl = $request->session()->get('saml_slo_redirect_url'); + + if (!empty($auth->getSLOurl()) && $settings->saml_slo == '1' && $saml->isAuthenticated() && empty($sloRedirectUrl)) { + $sloRequestUrl = $auth->logout(null, array(), $saml->getNameId(), $saml->getSessionIndex(), true, $saml->getNameIdFormat(), $saml->getNameIdNameQualifier(), $saml->getNameIdSPNameQualifier()); + } + + $saml->clearData(); + } + + if (!empty($sloRequestUrl)) { + return redirect()->away($sloRequestUrl); + } + + $request->session()->regenerate(true); $request->session()->regenerate(true); Auth::logout(); - $settings = Setting::getSettings(); + if (!empty($sloRedirectUrl)) { + return redirect()->away($sloRedirectUrl); + } + $customLogoutUrl = $settings->login_remote_user_custom_logout_url ; if ($settings->login_remote_user_enabled == '1' && $customLogoutUrl != '') { return redirect()->away($customLogoutUrl); } - return redirect()->route('login')->with('success', trans('auth/message.logout.success')); + return redirect()->route('login')->with(['success' => trans('auth/message.logout.success'), 'loggedout' => true]); } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 146974df96..901af3e2d0 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\ResetsPasswords; class RegisterController extends Controller { diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index ac31e273cb..540abc1f30 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -4,7 +4,6 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; -use App\Models\User; use Illuminate\Http\Request; class ResetPasswordController extends Controller @@ -39,7 +38,36 @@ class ResetPasswordController extends Controller $this->middleware('guest'); } - + protected function rules() + { + return [ + 'token' => 'required', + 'username' => 'required', + 'password' => 'required|confirmed|min:6', + ]; + } + protected function credentials(Request $request) + { + return $request->only( + 'username', 'password', 'password_confirmation', 'token' + ); + } + + + public function showResetForm(Request $request, $token = null) + { + return view('auth.passwords.reset')->with( + ['token' => $token, 'username' => $request->input('username')] + ); + } + + protected function sendResetFailedResponse(Request $request, $response) + { + return redirect()->back() + ->withInput(['username'=>$request->input('username')]) + ->withErrors(['username' => trans($response)]); + } + } diff --git a/app/Http/Controllers/Auth/SamlController.php b/app/Http/Controllers/Auth/SamlController.php new file mode 100644 index 0000000000..b5a63a3238 --- /dev/null +++ b/app/Http/Controllers/Auth/SamlController.php @@ -0,0 +1,140 @@ + + * + * @since 5.0.0 + */ +class SamlController extends Controller +{ + /** + * @var Saml + */ + protected $saml; + + /** + * Create a new authentication controller instance. + * + * @return void + */ + public function __construct(Saml $saml) + { + $this->saml = $saml; + + $this->middleware('guest', ['except' => ['metadata','sls']]); + } + + /** + * Return SAML SP metadata for Snipe-IT + * + * /saml/metadata + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param Request $request + * + * @return Response + */ + public function metadata(Request $request) + { + $metadata = $this->saml->getSPMetadata(); + + if (empty($metadata)) { + return response()->view('errors.403', [], 403); + } + + return response($metadata)->header('Content-Type', 'text/xml'); + } + + /** + * Begin the SP-Initiated SSO by sending AuthN to the IdP. + * + * /login/saml + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param Request $request + * + * @return Redirect + */ + public function login(Request $request) + { + $auth = $this->saml->getAuth(); + $ssoUrl = $auth->login(null, array(), false, false, false, false); + return redirect()->away($ssoUrl); + } + + /** + * Receives, parses the assertion from IdP and flashes SAML data + * back to the LoginController for authentication. + * + * /saml/acs + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param Request $request + * + * @return Redirect + */ + public function acs(Request $request) + { + $saml = $this->saml; + $auth = $saml->getAuth(); + $auth->processResponse(); + $errors = $auth->getErrors(); + + if (!empty($errors)) { + Log::debug("There was an error with SAML ACS: " . implode(', ', $errors)); + Log::debug("Reason: " . $auth->getLastErrorReason()); + return redirect()->route('login')->with('error', trans('auth/message.signin.error')); + } + + $samlData = $saml->extractData(); + + return redirect()->route('login')->with('saml_login', $samlData); + } + + /** + * Receives LogoutRequest/LogoutResponse from IdP and flashes + * back to the LoginController for logging out. + * + * /saml/slo + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param Request $request + * + * @return Redirect + */ + public function sls(Request $request) + { + $auth = $this->saml->getAuth(); + $sloUrl = $auth->processSLO(true, null, null, null, true); + $errors = $auth->getErrors(); + + if (!empty($errors)) { + Log::debug("There was an error with SAML SLS: " . implode(', ', $errors)); + Log::debug("Reason: " . $auth->getLastErrorReason()); + return view('errors.403'); + } + + return redirect()->route('logout')->with('saml_slo_redirect_url', $sloUrl); + } +} diff --git a/app/Http/Controllers/BulkAssetModelsController.php b/app/Http/Controllers/BulkAssetModelsController.php new file mode 100644 index 0000000000..088e8da509 --- /dev/null +++ b/app/Http/Controllers/BulkAssetModelsController.php @@ -0,0 +1,138 @@ +] + * @since [v1.7] + * @param Request $request + * @return \Illuminate\Contracts\View\View + */ + public function edit(Request $request) + { + $models_raw_array = $request->input('ids'); + + // Make sure some IDs have been selected + if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) { + + $models = AssetModel::whereIn('id', $models_raw_array) + ->withCount('assets as assets_count') + ->orderBy('assets_count', 'ASC') + ->get(); + + // If deleting.... + if ($request->input('bulk_actions')=='delete') { + $valid_count = 0; + foreach ($models as $model) { + if ($model->assets_count == 0) { + $valid_count++; + } + } + return view('models/bulk-delete', compact('models'))->with('valid_count', $valid_count); + + // Otherwise display the bulk edit screen + } + + $nochange = ['NC' => 'No Change']; + return view('models/bulk-edit', compact('models')) + ->with('fieldset_list', $nochange + Helper::customFieldsetList()) + ->with('depreciation_list', $nochange + Helper::depreciationList()); + } + + return redirect()->route('models.index') + ->with('error', 'You must select at least one model to edit.'); + } + + /** + * Returns a view that allows the user to bulk edit model attrbutes + * + * @author [A. Gianotto] [] + * @since [v1.7] + * @param Request $request + * @return \Illuminate\Contracts\View\View + */ + public function update(Request $request) + { + + $models_raw_array = $request->input('ids'); + $update_array = array(); + + if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) { + $update_array['manufacturer_id'] = $request->input('manufacturer_id'); + } + if (($request->filled('category_id') && ($request->input('category_id')!='NC'))) { + $update_array['category_id'] = $request->input('category_id'); + } + if ($request->input('fieldset_id')!='NC') { + $update_array['fieldset_id'] = $request->input('fieldset_id'); + } + if ($request->input('depreciation_id')!='NC') { + $update_array['depreciation_id'] = $request->input('depreciation_id'); + } + + + + if (count($update_array) > 0) { + AssetModel::whereIn('id', $models_raw_array)->update($update_array); + return redirect()->route('models.index') + ->with('success', trans('admin/models/message.bulkedit.success')); + } + + return redirect()->route('models.index') + ->with('warning', trans('admin/models/message.bulkedit.error')); + + } + + /** + * Validate and delete the given Asset Models. An Asset Model + * cannot be deleted if there are associated assets. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return Redirect + */ + public function destroy(Request $request) + { + $models_raw_array = $request->input('ids'); + + if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) { + + $models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->get(); + + $del_error_count = 0; + $del_count = 0; + + foreach ($models as $model) { + if ($model->assets_count > 0) { + $del_error_count++; + } else { + $model->delete(); + $del_count++; + } + } + + if ($del_error_count == 0) { + return redirect()->route('models.index') + ->with('success', trans('admin/models/message.bulkdelete.success',['success_count'=> $del_count] )); + } + + return redirect()->route('models.index') + ->with('warning', trans('admin/models/message.bulkdelete.success_partial', ['fail_count'=>$del_error_count, 'success_count'=> $del_count])); + } + + return redirect()->route('models.index') + ->with('error', trans('admin/models/message.bulkdelete.error')); + + } + +} diff --git a/app/Http/Controllers/CategoriesController.php b/app/Http/Controllers/CategoriesController.php index a2f33ebb0a..244a687ede 100755 --- a/app/Http/Controllers/CategoriesController.php +++ b/app/Http/Controllers/CategoriesController.php @@ -2,21 +2,11 @@ namespace App\Http\Controllers; use App\Helpers\Helper; -use App\Models\Category as Category; -use App\Models\Company; -use App\Models\CustomField; -use App\Models\Setting; -use Auth; -use DB; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Gate; -use Input; -use Lang; -use Redirect; -use Str; -use View; -use Image; use App\Http\Requests\ImageUploadRequest; +use App\Models\Category as Category; +use Auth; +use Illuminate\Support\Facades\Storage; +use Str; /** * This class controls all actions related to Categories for @@ -29,13 +19,14 @@ class CategoriesController extends Controller { /** - * Returns a view that invokes the ajax tables which actually contains - * the content for the categories listing, which is generated in getDatatable. - * - * @author [A. Gianotto] [] - * @see CategoriesController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that invokes the ajax tables which actually contains + * the content for the categories listing, which is generated in getDatatable. + * + * @author [A. Gianotto] [] + * @see CategoriesController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index() { @@ -46,30 +37,32 @@ class CategoriesController extends Controller /** - * Returns a form view to create a new category. - * - * @author [A. Gianotto] [] - * @see CategoriesController::store() method that stores the data - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a form view to create a new category. + * + * @author [A. Gianotto] [] + * @see CategoriesController::store() method that stores the data + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create() { // Show the page $this->authorize('create', Category::class); - $category_types= Helper::categoryTypeList(); return view('categories/edit')->with('item', new Category) - ->with('category_types', $category_types); + ->with('category_types', Helper::categoryTypeList()); } /** - * Validates and stores the new category data. - * - * @author [A. Gianotto] [] - * @see CategoriesController::create() method that makes the form. - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse + * Validates and stores the new category data. + * + * @author [A. Gianotto] [] + * @see CategoriesController::create() method that makes the form. + * @since [v1.0] + * @param ImageUploadRequest $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(ImageUploadRequest $request) { @@ -83,8 +76,7 @@ class CategoriesController extends Controller $category->checkin_email = $request->input('checkin_email', '0'); $category->user_id = Auth::id(); - $category = $request->handleImages($category,600, public_path().'/uploads/categories'); - + $category = $request->handleImages($category); if ($category->save()) { return redirect()->route('categories.index')->with('success', trans('admin/categories/message.create.success')); } @@ -93,24 +85,23 @@ class CategoriesController extends Controller } /** - * Returns a view that makes a form to update a category. - * - * @author [A. Gianotto] [] - * @see CategoriesController::postEdit() method saves the data - * @param int $categoryId - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that makes a form to update a category. + * + * @author [A. Gianotto] [] + * @see CategoriesController::postEdit() method saves the data + * @param int $categoryId + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit($categoryId = null) { - $this->authorize('edit', Category::class); + $this->authorize('update', Category::class); if (is_null($item = Category::find($categoryId))) { return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist')); } - $category_types= Helper::categoryTypeList(); - return view('categories/edit', compact('item')) - ->with('category_types', $category_types); + ->with('category_types', Helper::categoryTypeList()); } @@ -119,14 +110,15 @@ class CategoriesController extends Controller * * @author [A. Gianotto] [] * @see CategoriesController::getEdit() method that makes the form. - * @param Request $request + * @param ImageUploadRequest $request * @param int $categoryId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException * @since [v1.0] */ public function update(ImageUploadRequest $request, $categoryId = null) { - $this->authorize('edit', Category::class); + $this->authorize('update', Category::class); if (is_null($category = Category::find($categoryId))) { // Redirect to the categories management page return redirect()->to('admin/categories')->with('error', trans('admin/categories/message.does_not_exist')); @@ -142,12 +134,8 @@ class CategoriesController extends Controller $category->require_acceptance = $request->input('require_acceptance', '0'); $category->checkin_email = $request->input('checkin_email', '0'); - // Set the model's image property to null if the image is being deleted - if ($request->input('image_delete') == 1) { - $category->image = null; - } - $category = $request->handleImages($category,600, public_path().'/uploads/categories'); + $category = $request->handleImages($category); if ($category->save()) { // Redirect to the new category page @@ -158,31 +146,27 @@ class CategoriesController extends Controller } /** - * Validates and marks a category as deleted. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $categoryId - * @return \Illuminate\Http\RedirectResponse + * Validates and marks a category as deleted. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $categoryId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($categoryId) { $this->authorize('delete', Category::class); // Check if the category exists - if (is_null($category = Category::find($categoryId))) { + if (is_null($category = Category::findOrFail($categoryId))) { return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found')); } - if ($category->has_models() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'model'])); - } elseif ($category->accessories()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory'])); - } elseif ($category->consumables()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable'])); - } elseif ($category->components()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component'])); + if (!$category->isDeletable()) { + return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=> $category->category_type ])); } + Storage::disk('public')->delete('categories'.'/'.$category->image); $category->delete(); // Redirect to the locations management page return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success')); @@ -190,14 +174,15 @@ class CategoriesController extends Controller /** - * Returns a view that invokes the ajax tables which actually contains - * the content for the categories detail view, which is generated in getDataView. - * - * @author [A. Gianotto] [] - * @see CategoriesController::getDataView() method that generates the JSON response - * @param int $categoryId - * @since [v1.8] - * @return \Illuminate\Contracts\View\View + * Returns a view that invokes the ajax tables which actually contains + * the content for the categories detail view, which is generated in getDataView. + * + * @author [A. Gianotto] [] + * @see CategoriesController::getDataView() method that generates the JSON response + * @param $id + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v1.8] */ public function show($id) { @@ -221,6 +206,4 @@ class CategoriesController extends Controller return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist')); } - - } diff --git a/app/Http/Controllers/CheckInOutRequest.php b/app/Http/Controllers/CheckInOutRequest.php index f88d6acda7..f080dac4e3 100644 --- a/app/Http/Controllers/CheckInOutRequest.php +++ b/app/Http/Controllers/CheckInOutRequest.php @@ -1,9 +1,9 @@ ] - * @since [v1.8] - * @return \Illuminate\Contracts\View\View + * Returns view to display listing of companies. + * + * @author [Abdullah Alansari] [] + * @since [v1.8] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index() { @@ -35,11 +32,12 @@ final class CompaniesController extends Controller } /** - * Returns view to create a new company. - * - * @author [Abdullah Alansari] [] - * @since [v1.8] - * @return \Illuminate\Contracts\View\View + * Returns view to create a new company. + * + * @author [Abdullah Alansari] [] + * @since [v1.8] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create() { @@ -55,6 +53,7 @@ final class CompaniesController extends Controller * @since [v1.8] * @param Request $request * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(ImageUploadRequest $request) { @@ -63,7 +62,7 @@ final class CompaniesController extends Controller $company = new Company; $company->name = $request->input('name'); - $company = $request->handleImages($company,600, public_path().'/uploads/companies'); + $company = $request->handleImages($company); if ($company->save()) { return redirect()->route('companies.index') @@ -74,12 +73,13 @@ final class CompaniesController extends Controller /** - * Return form to edit existing company. - * - * @author [Abdullah Alansari] [] - * @since [v1.8] - * @param int $companyId - * @return \Illuminate\Contracts\View\View + * Return form to edit existing company. + * + * @author [Abdullah Alansari] [] + * @since [v1.8] + * @param int $companyId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit($companyId) { @@ -98,9 +98,10 @@ final class CompaniesController extends Controller * * @author [Abdullah Alansari] [] * @since [v1.8] - * @param Request $request + * @param ImageUploadRequest $request * @param int $companyId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(ImageUploadRequest $request, $companyId) { @@ -112,12 +113,8 @@ final class CompaniesController extends Controller $company->name = $request->input('name'); - // Set the model's image property to null if the image is being deleted - if ($request->input('image_delete') == 1) { - $company->image = null; - } - $company = $request->handleImages($company,600, public_path().'/uploads/companies'); + $company = $request->handleImages($company); if ($company->save()) { @@ -129,39 +126,38 @@ final class CompaniesController extends Controller } /** - * Delete company - * - * @author [Abdullah Alansari] [] - * @since [v1.8] - * @param int $companyId - * @return \Illuminate\Http\RedirectResponse + * Delete company + * + * @author [Abdullah Alansari] [] + * @since [v1.8] + * @param int $companyId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($companyId) { if (is_null($company = Company::find($companyId))) { return redirect()->route('companies.index') ->with('error', trans('admin/companies/message.not_found')); - } else { + } - $this->authorize('delete', $company); + $this->authorize('delete', $company); + if(!$company->isDeletable()) { + return redirect()->route('companies.index') + ->with('error', trans('admin/companies/message.assoc_users')); + } - try { - $company->delete(); - return redirect()->route('companies.index') - ->with('success', trans('admin/companies/message.delete.success')); - } catch (\Illuminate\Database\QueryException $exception) { - /* - * NOTE: This happens when there's a foreign key constraint violation - * For example when rows in other tables are referencing this company - */ - if ($exception->getCode() == 23000) { - return redirect()->route('companies.index') - ->with('error', trans('admin/companies/message.assoc_users')); - } else { - throw $exception; - } + if ($company->image) { + try { + Storage::disk('public')->delete('companies'.'/'.$company->image); + } catch (\Exception $e) { + \Log::debug($e); } } + + $company->delete(); + return redirect()->route('companies.index') + ->with('success', trans('admin/companies/message.delete.success')); } public function show($id) { @@ -170,9 +166,8 @@ final class CompaniesController extends Controller if (is_null($company = Company::find($id))) { return redirect()->route('companies.index') ->with('error', trans('admin/companies/message.not_found')); - } else { - return view('companies/view')->with('company',$company); } + return view('companies/view')->with('company',$company); } } diff --git a/app/Http/Controllers/Components/ComponentCheckinController.php b/app/Http/Controllers/Components/ComponentCheckinController.php new file mode 100644 index 0000000000..eee0f15827 --- /dev/null +++ b/app/Http/Controllers/Components/ComponentCheckinController.php @@ -0,0 +1,108 @@ +] + * @see ComponentCheckinController::store() method that stores the data. + * @since [v4.1.4] + * @param $component_asset_id + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($component_asset_id) + { + + // This could probably be done more cleanly but I am very tired. - @snipe + if ($component_assets = DB::table('components_assets')->find($component_asset_id)) { + if (is_null($component = Component::find($component_assets->component_id))) { + return redirect()->route('components.index')->with('error', trans('admin/components/messages.not_found')); + } + if (is_null($asset = Asset::find($component_assets->asset_id))) { + return redirect()->route('components.index')->with('error', + trans('admin/components/message.not_found')); + } + $this->authorize('checkin', $component); + return view('components/checkin', compact('component_assets','component','asset')); + } + + return redirect()->route('components.index')->with('error', trans('admin/components/messages.not_found')); + + } + + + /** + * Validate and store checkin data. + * + * @author [A. Gianotto] [] + * @see ComponentCheckinController::create() method that returns the form. + * @since [v4.1.4] + * @param Request $request + * @param $component_asset_id + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request, $component_asset_id) + { + if ($component_assets = DB::table('components_assets')->find($component_asset_id)) { + if (is_null($component = Component::find($component_assets->component_id))) { + return redirect()->route('components.index')->with('error', + trans('admin/components/message.not_found')); + } + + + $this->authorize('checkin', $component); + + $max_to_checkin = $component_assets->assigned_qty; + $validator = Validator::make($request->all(), [ + "checkin_qty" => "required|numeric|between:1,$max_to_checkin" + ]); + + if ($validator->fails()) { + return redirect()->back() + ->withErrors($validator) + ->withInput(); + } + + // Validation passed, so let's figure out what we have to do here. + $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty')); + + // We have to modify the record to reflect the new qty that's + // actually checked out. + $component_assets->assigned_qty = $qty_remaining_in_checkout; + DB::table('components_assets')->where('id', + $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]); + + // If the checked-in qty is exactly the same as the assigned_qty, + // we can simply delete the associated components_assets record + if ($qty_remaining_in_checkout == 0) { + DB::table('components_assets')->where('id', '=', $component_asset_id)->delete(); + } + + $asset = Asset::find($component_assets->asset_id); + + event(new CheckoutableCheckedIn($component, $asset, Auth::user(), $request->input('note'), Carbon::now())); + + return redirect()->route('components.index')->with('success', + trans('admin/components/message.checkin.success')); + } + return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); + } + +} diff --git a/app/Http/Controllers/Components/ComponentCheckoutController.php b/app/Http/Controllers/Components/ComponentCheckoutController.php new file mode 100644 index 0000000000..4ae37dbd0a --- /dev/null +++ b/app/Http/Controllers/Components/ComponentCheckoutController.php @@ -0,0 +1,95 @@ +] + * @see ComponentCheckoutController::store() method that stores the data. + * @since [v3.0] + * @param int $componentId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($componentId) + { + // Check if the component exists + if (is_null($component = Component::find($componentId))) { + // Redirect to the component management page with error + return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found')); + } + $this->authorize('checkout', $component); + return view('components/checkout', compact('component')); + } + + /** + * Validate and store checkout data. + * + * @author [A. Gianotto] [] + * @see ComponentCheckoutController::create() method that returns the form. + * @since [v3.0] + * @param Request $request + * @param int $componentId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request, $componentId) + { + // Check if the component exists + if (is_null($component = Component::find($componentId))) { + // Redirect to the component management page with error + return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found')); + } + + $this->authorize('checkout', $component); + + $max_to_checkout = $component->numRemaining(); + $validator = Validator::make($request->all(), [ + "asset_id" => "required", + "assigned_qty" => "required|numeric|between:1,$max_to_checkout" + ]); + + if ($validator->fails()) { + return redirect()->back() + ->withErrors($validator) + ->withInput(); + } + + $admin_user = Auth::user(); + $asset_id = e($request->input('asset_id')); + + // Check if the user exists + if (is_null($asset = Asset::find($asset_id))) { + // Redirect to the component management page with error + return redirect()->route('components.index')->with('error', trans('admin/components/message.asset_does_not_exist')); + } + + // Update the component data + $component->asset_id = $asset_id; + + $component->assets()->attach($component->id, [ + 'component_id' => $component->id, + 'user_id' => $admin_user->id, + 'created_at' => date('Y-m-d H:i:s'), + 'assigned_qty' => $request->input('assigned_qty'), + 'asset_id' => $asset_id + ]); + + event(new CheckoutableCheckedOut($component, $asset, Auth::user(), $request->input('note'))); + + return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success')); + } +} diff --git a/app/Http/Controllers/Components/ComponentsController.php b/app/Http/Controllers/Components/ComponentsController.php new file mode 100644 index 0000000000..9fde48df41 --- /dev/null +++ b/app/Http/Controllers/Components/ComponentsController.php @@ -0,0 +1,210 @@ +] + * @see ComponentsController::getDatatable() method that generates the JSON response + * @since [v3.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('view', Component::class); + return view('components/index'); + } + + + /** + * Returns a form to create a new component. + * + * @author [A. Gianotto] [] + * @see ComponentsController::postCreate() method that stores the data + * @since [v3.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create() + { + $this->authorize('create', Component::class); + return view('components/edit')->with('category_type', 'component') + ->with('item', new Component); + } + + + /** + * Validate and store data for new component. + * + * @author [A. Gianotto] [] + * @see ComponentsController::getCreate() method that generates the view + * @since [v3.0] + * @param ImageUploadRequest $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(ImageUploadRequest $request) + { + $this->authorize('create', Component::class); + $component = new Component(); + $component->name = $request->input('name'); + $component->category_id = $request->input('category_id'); + $component->location_id = $request->input('location_id'); + $component->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $component->order_number = $request->input('order_number', null); + $component->min_amt = $request->input('min_amt', null); + $component->serial = $request->input('serial', null); + $component->purchase_date = $request->input('purchase_date', null); + $component->purchase_cost = $request->input('purchase_cost', null); + $component->qty = $request->input('qty'); + $component->user_id = Auth::id(); + + $component = $request->handleImages($component); + + if ($component->save()) { + return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success')); + } + return redirect()->back()->withInput()->withErrors($component->getErrors()); + } + + /** + * Return a view to edit a component. + * + * @author [A. Gianotto] [] + * @see ComponentsController::postEdit() method that stores the data. + * @since [v3.0] + * @param int $componentId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit($componentId = null) + { + if ($item = Component::find($componentId)) { + $this->authorize('update', $item); + return view('components/edit', compact('item'))->with('category_type', 'component'); + } + return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); + } + + + /** + * Return a view to edit a component. + * + * @author [A. Gianotto] [] + * @see ComponentsController::getEdit() method presents the form. + * @param ImageUploadRequest $request + * @param int $componentId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v3.0] + */ + public function update(ImageUploadRequest $request, $componentId = null) + { + if (is_null($component = Component::find($componentId))) { + return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); + } + $min = $component->numCHeckedOut(); + $validator = Validator::make($request->all(), [ + "qty" => "required|numeric|gt:$min" + ]); + + if ($validator->fails()) { + return redirect()->back() + ->withErrors($validator) + ->withInput(); + } + + $this->authorize('update', $component); + + // Update the component data + $component->name = $request->input('name'); + $component->category_id = $request->input('category_id'); + $component->location_id = $request->input('location_id'); + $component->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $component->order_number = $request->input('order_number'); + $component->min_amt = $request->input('min_amt'); + $component->serial = $request->input('serial'); + $component->purchase_date = $request->input('purchase_date'); + $component->purchase_cost = request('purchase_cost'); + $component->qty = $request->input('qty'); + + $component = $request->handleImages($component); + + if ($component->save()) { + return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success')); + } + return redirect()->back()->withInput()->withErrors($component->getErrors()); + } + + /** + * Delete a component. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @param int $componentId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($componentId) + { + if (is_null($component = Component::find($componentId))) { + return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); + } + + $this->authorize('delete', $component); + + // Remove the image if one exists + if (Storage::disk('public')->exists('components/'.$component->image)) { + try { + Storage::disk('public')->delete('components/'.$component->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + + $component->delete(); + return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success')); + } + + /** + * Return a view to display component information. + * + * @author [A. Gianotto] [] + * @see ComponentsController::getDataView() method that generates the JSON response + * @since [v3.0] + * @param int $componentId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($componentId = null) + { + $component = Component::find($componentId); + + if (isset($component->id)) { + $this->authorize('view', $component); + return view('components/view', compact('component')); + } + // Redirect to the user management page + return redirect()->route('components.index') + ->with('error', trans('admin/components/message.does_not_exist')); + } +} diff --git a/app/Http/Controllers/ComponentsController.php b/app/Http/Controllers/ComponentsController.php deleted file mode 100644 index 4bd7ec97c3..0000000000 --- a/app/Http/Controllers/ComponentsController.php +++ /dev/null @@ -1,375 +0,0 @@ -] - * @see ComponentsController::getDatatable() method that generates the JSON response - * @since [v3.0] - * @return \Illuminate\Contracts\View\View - */ - public function index() - { - $this->authorize('view', Component::class); - return view('components/index'); - } - - - /** - * Returns a form to create a new component. - * - * @author [A. Gianotto] [] - * @see ComponentsController::postCreate() method that stores the data - * @since [v3.0] - * @return \Illuminate\Contracts\View\View - */ - public function create() - { - $this->authorize('create', Component::class); - $category_type = 'component'; - return view('components/edit')->with('category_type',$category_type) - ->with('item', new Component); - } - - - /** - * Validate and store data for new component. - * - * @author [A. Gianotto] [] - * @see ComponentsController::getCreate() method that generates the view - * @since [v3.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function store(ImageUploadRequest $request) - { - $this->authorize('create', Component::class); - $component = new Component(); - $component->name = $request->input('name'); - $component->category_id = $request->input('category_id'); - $component->location_id = $request->input('location_id'); - $component->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $component->order_number = $request->input('order_number', null); - $component->min_amt = $request->input('min_amt', null); - $component->serial = $request->input('serial', null); - $component->purchase_date = $request->input('purchase_date', null); - $component->purchase_cost = $request->input('purchase_cost', null); - $component->qty = $request->input('qty'); - $component->user_id = Auth::id(); - - - $component = $request->handleImages($component,600, public_path().'/uploads/components'); - - if ($component->save()) { - return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success')); - } - return redirect()->back()->withInput()->withErrors($component->getErrors()); - } - - /** - * Return a view to edit a component. - * - * @author [A. Gianotto] [] - * @see ComponentsController::postEdit() method that stores the data. - * @since [v3.0] - * @param int $componentId - * @return \Illuminate\Contracts\View\View - */ - public function edit($componentId = null) - { - - - if ($item = Component::find($componentId)) { - $this->authorize('update', $item); - $category_type = 'component'; - return view('components/edit', compact('item'))->with('category_type', $category_type); - } - return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); - - - - - } - - - /** - * Return a view to edit a component. - * - * @author [A. Gianotto] [] - * @see ComponentsController::getEdit() method presents the form. - * @param int $componentId - * @since [v3.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function update(ImageUploadRequest $request, $componentId = null) - { - if (is_null($component = Component::find($componentId))) { - return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); - } - - $this->authorize('update', $component); - - - // Update the component data - $component->name = Input::get('name'); - $component->category_id = Input::get('category_id'); - $component->location_id = Input::get('location_id'); - $component->company_id = Company::getIdForCurrentUser(Input::get('company_id')); - $component->order_number = Input::get('order_number'); - $component->min_amt = Input::get('min_amt'); - $component->serial = Input::get('serial'); - $component->purchase_date = Input::get('purchase_date'); - $component->purchase_cost = request('purchase_cost'); - $component->qty = Input::get('qty'); - - $component = $request->handleImages($component,600, public_path().'/uploads/components'); - - if ($component->save()) { - return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success')); - } - return redirect()->back()->withInput()->withErrors($component->getErrors()); - } - - /** - * Delete a component. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @param int $componentId - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy($componentId) - { - if (is_null($component = Component::find($componentId))) { - return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); - } - - $this->authorize('delete', $component); - $component->delete(); - return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success')); - } - - /** - * Return a view to display component information. - * - * @author [A. Gianotto] [] - * @see ComponentsController::getDataView() method that generates the JSON response - * @since [v3.0] - * @param int $componentId - * @return \Illuminate\Contracts\View\View - */ - public function show($componentId = null) - { - $component = Component::find($componentId); - - if (isset($component->id)) { - $this->authorize('view', $component); - return view('components/view', compact('component')); - } - - return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); - } - - /** - * Returns a view that allows the checkout of a component to an asset. - * - * @author [A. Gianotto] [] - * @see ComponentsController::postCheckout() method that stores the data. - * @since [v3.0] - * @param int $componentId - * @return \Illuminate\Contracts\View\View - */ - public function getCheckout($componentId) - { - // Check if the component exists - if (is_null($component = Component::find($componentId))) { - // Redirect to the component management page with error - return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found')); - } - $this->authorize('checkout', $component); - return view('components/checkout', compact('component')); - } - - /** - * Validate and store checkout data. - * - * @author [A. Gianotto] [] - * @see ComponentsController::getCheckout() method that returns the form. - * @since [v3.0] - * @param Request $request - * @param int $componentId - * @return \Illuminate\Http\RedirectResponse - */ - public function postCheckout(Request $request, $componentId) - { - // Check if the component exists - if (is_null($component = Component::find($componentId))) { - // Redirect to the component management page with error - return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found')); - } - - $this->authorize('checkout', $component); - - $max_to_checkout = $component->numRemaining(); - $validator = Validator::make($request->all(), [ - "asset_id" => "required", - "assigned_qty" => "required|numeric|between:1,$max_to_checkout" - ]); - - if ($validator->fails()) { - return redirect()->back() - ->withErrors($validator) - ->withInput(); - } - - $admin_user = Auth::user(); - $asset_id = e(Input::get('asset_id')); - - // Check if the user exists - if (is_null($asset = Asset::find($asset_id))) { - // Redirect to the component management page with error - return redirect()->route('components.index')->with('error', trans('admin/components/message.asset_does_not_exist')); - } - - // Update the component data - $component->asset_id = $asset_id; - - $component->assets()->attach($component->id, [ - 'component_id' => $component->id, - 'user_id' => $admin_user->id, - 'created_at' => date('Y-m-d H:i:s'), - 'assigned_qty' => Input::get('assigned_qty'), - 'asset_id' => $asset_id - ]); - - $component->logCheckout(e(Input::get('note')), $asset); - return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success')); - } - - /** - * Returns a view that allows the checkin of a component from an asset. - * - * @author [A. Gianotto] [] - * @see ComponentsController::postCheckout() method that stores the data. - * @since [v4.1.4] - * @param int $componentId - * @return \Illuminate\Contracts\View\View - */ - public function getCheckin($component_asset_id) - { - - // This could probably be done more cleanly but I am very tired. - @snipe - if ($component_assets = DB::table('components_assets')->find($component_asset_id)) { - if (is_null($component = Component::find($component_assets->component_id))) { - return redirect()->route('components.index')->with('error', trans('admin/components/messages.not_found')); - } - if (is_null($asset = Asset::find($component_assets->asset_id))) { - return redirect()->route('components.index')->with('error', - trans('admin/components/message.not_found')); - } - $this->authorize('checkin', $component); - return view('components/checkin', compact('component_assets','component','asset')); - } - - return redirect()->route('components.index')->with('error', trans('admin/components/messages.not_found')); - - } - - /** - * Validate and store checkin data. - * - * @author [A. Gianotto] [] - * @see ComponentsController::getCheckout() method that returns the form. - * @since [v4.1.4] - * @param Request $request - * @param int $componentId - * @return \Illuminate\Http\RedirectResponse - */ - public function postCheckin(Request $request, $component_asset_id) - { - if ($component_assets = DB::table('components_assets')->find($component_asset_id)) { - if (is_null($component = Component::find($component_assets->component_id))) { - return redirect()->route('components.index')->with('error', - trans('admin/components/message.not_found')); - } - - - $this->authorize('checkin', $component); - - $max_to_checkin = $component_assets->assigned_qty; - $validator = Validator::make($request->all(), [ - "checkin_qty" => "required|numeric|between:1,$max_to_checkin" - ]); - - if ($validator->fails()) { - return redirect()->back() - ->withErrors($validator) - ->withInput(); - } - - // Validation passed, so let's figure out what we have to do here. - $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty')); - - // We have to modify the record to reflect the new qty that's - // actually checked out. - $component_assets->assigned_qty = $qty_remaining_in_checkout; - DB::table('components_assets')->where('id', - $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]); - - $log = new Actionlog(); - $log->user_id = Auth::user()->id; - $log->action_type = 'checkin from'; - $log->target_type = Asset::class; - $log->target_id = $component_assets->asset_id; - $log->item_id = $component_assets->component_id; - $log->item_type = Component::class; - $log->note = $request->input('note'); - $log->save(); - - // If the checked-in qty is exactly the same as the assigned_qty, - // we can simply delete the associated components_assets record - if ($qty_remaining_in_checkout == 0) { - DB::table('components_assets')->where('id', '=', $component_asset_id)->delete(); - } - - return redirect()->route('components.index')->with('success', - trans('admin/components/message.checkout.success')); - } - return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found')); - } - - -} diff --git a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php new file mode 100644 index 0000000000..8dc43b54c1 --- /dev/null +++ b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php @@ -0,0 +1,77 @@ +] + * @see ConsumableCheckoutController::store() method that stores the data. + * @since [v1.0] + * @param int $consumableId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($consumableId) + { + if (is_null($consumable = Consumable::find($consumableId))) { + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); + } + $this->authorize('checkout', $consumable); + return view('consumables/checkout', compact('consumable')); + } + + /** + * Saves the checkout information + * + * @author [A. Gianotto] [] + * @see ConsumableCheckoutController::create() method that returns the form. + * @since [v1.0] + * @param int $consumableId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request, $consumableId) + { + if (is_null($consumable = Consumable::find($consumableId))) { + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found')); + } + + $this->authorize('checkout', $consumable); + + $admin_user = Auth::user(); + $assigned_to = e($request->input('assigned_to')); + + // Check if the user exists + if (is_null($user = User::find($assigned_to))) { + // Redirect to the consumable management page with error + return redirect()->route('checkout/consumable', $consumable)->with('error', trans('admin/consumables/message.checkout.user_does_not_exist')); + } + + // Update the consumable data + $consumable->assigned_to = e($request->input('assigned_to')); + + $consumable->users()->attach($consumable->id, [ + 'consumable_id' => $consumable->id, + 'user_id' => $admin_user->id, + 'assigned_to' => e($request->input('assigned_to')) + ]); + + event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note'))); + + // Redirect to the new consumable page + return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success')); + + } +} diff --git a/app/Http/Controllers/Consumables/ConsumablesController.php b/app/Http/Controllers/Consumables/ConsumablesController.php new file mode 100644 index 0000000000..69987f1570 --- /dev/null +++ b/app/Http/Controllers/Consumables/ConsumablesController.php @@ -0,0 +1,196 @@ +] + * @see ConsumablesController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('index', Consumable::class); + return view('consumables/index'); + } + + + /** + * Return a view to display the form view to create a new consumable + * + * @author [A. Gianotto] [] + * @see ConsumablesController::postCreate() method that stores the form data + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create() + { + $this->authorize('create', Consumable::class); + return view('consumables/edit')->with('category_type', 'consumable') + ->with('item', new Consumable); + } + + + /** + * Validate and store new consumable data. + * + * @author [A. Gianotto] [] + * @see ConsumablesController::getCreate() method that returns the form view + * @since [v1.0] + * @param ImageUploadRequest $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(ImageUploadRequest $request) + { + $this->authorize('create', Consumable::class); + $consumable = new Consumable(); + $consumable->name = $request->input('name'); + $consumable->category_id = $request->input('category_id'); + $consumable->location_id = $request->input('location_id'); + $consumable->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $consumable->order_number = $request->input('order_number'); + $consumable->min_amt = $request->input('min_amt'); + $consumable->manufacturer_id = $request->input('manufacturer_id'); + $consumable->model_number = $request->input('model_number'); + $consumable->item_no = $request->input('item_no'); + $consumable->purchase_date = $request->input('purchase_date'); + $consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost')); + $consumable->qty = $request->input('qty'); + $consumable->user_id = Auth::id(); + + + $consumable = $request->handleImages($consumable); + + if ($consumable->save()) { + return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.create.success')); + } + + return redirect()->back()->withInput()->withErrors($consumable->getErrors()); + + } + + /** + * Returns a form view to edit a consumable. + * + * @author [A. Gianotto] [] + * @param int $consumableId + * @see ConsumablesController::postEdit() method that stores the form data. + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit($consumableId = null) + { + if ($item = Consumable::find($consumableId)) { + $this->authorize($item); + return view('consumables/edit', compact('item'))->with('category_type', 'consumable'); + } + + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); + + } + + + /** + * Returns a form view to edit a consumable. + * + * @author [A. Gianotto] [] + * @param ImageUploadRequest $request + * @param int $consumableId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @see ConsumablesController::getEdit() method that stores the form data. + * @since [v1.0] + */ + public function update(ImageUploadRequest $request, $consumableId = null) + { + if (is_null($consumable = Consumable::find($consumableId))) { + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); + } + + $this->authorize($consumable); + + $consumable->name = $request->input('name'); + $consumable->category_id = $request->input('category_id'); + $consumable->location_id = $request->input('location_id'); + $consumable->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $consumable->order_number = $request->input('order_number'); + $consumable->min_amt = $request->input('min_amt'); + $consumable->manufacturer_id = $request->input('manufacturer_id'); + $consumable->model_number = $request->input('model_number'); + $consumable->item_no = $request->input('item_no'); + $consumable->purchase_date = $request->input('purchase_date'); + $consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost')); + $consumable->qty = Helper::ParseFloat($request->input('qty')); + + $consumable = $request->handleImages($consumable); + + if ($consumable->save()) { + return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.update.success')); + } + return redirect()->back()->withInput()->withErrors($consumable->getErrors()); + } + + /** + * Delete a consumable. + * + * @author [A. Gianotto] [] + * @param int $consumableId + * @since [v1.0] + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($consumableId) + { + if (is_null($consumable = Consumable::find($consumableId))) { + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found')); + } + $this->authorize($consumable); + $consumable->delete(); + // Redirect to the locations management page + return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.delete.success')); + } + + /** + * Return a view to display component information. + * + * @author [A. Gianotto] [] + * @see ConsumablesController::getDataView() method that generates the JSON response + * @since [v1.0] + * @param int $consumableId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($consumableId = null) + { + $consumable = Consumable::find($consumableId); + $this->authorize($consumable); + if (isset($consumable->id)) { + return view('consumables/view', compact('consumable')); + } + return redirect()->route('consumables.index') + ->with('error', trans('admin/consumables/message.does_not_exist')); + } + +} diff --git a/app/Http/Controllers/ConsumablesController.php b/app/Http/Controllers/ConsumablesController.php deleted file mode 100644 index f62d29fae1..0000000000 --- a/app/Http/Controllers/ConsumablesController.php +++ /dev/null @@ -1,278 +0,0 @@ -] - * @see ConsumablesController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function index() - { - $this->authorize('index', Consumable::class); - return view('consumables/index'); - } - - - /** - * Return a view to display the form view to create a new consumable - * - * @author [A. Gianotto] [] - * @see ConsumablesController::postCreate() method that stores the form data - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function create() - { - $this->authorize('create', Consumable::class); - $category_type = 'consumable'; - return view('consumables/edit')->with('category_type', $category_type) - ->with('item', new Consumable); - } - - - /** - * Validate and store new consumable data. - * - * @author [A. Gianotto] [] - * @see ConsumablesController::getCreate() method that returns the form view - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function store(ImageUploadRequest $request) - { - $this->authorize('create', Consumable::class); - $consumable = new Consumable(); - $consumable->name = $request->input('name'); - $consumable->category_id = $request->input('category_id'); - $consumable->location_id = $request->input('location_id'); - $consumable->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $consumable->order_number = $request->input('order_number'); - $consumable->min_amt = $request->input('min_amt'); - $consumable->manufacturer_id = $request->input('manufacturer_id'); - $consumable->model_number = $request->input('model_number'); - $consumable->item_no = $request->input('item_no'); - $consumable->purchase_date = $request->input('purchase_date'); - $consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost')); - $consumable->qty = $request->input('qty'); - $consumable->user_id = Auth::id(); - - - $consumable = $request->handleImages($consumable,600, public_path().'/uploads/components'); - - - if ($consumable->save()) { - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.create.success')); - } - - return redirect()->back()->withInput()->withErrors($consumable->getErrors()); - - } - - /** - * Returns a form view to edit a consumable. - * - * @author [A. Gianotto] [] - * @param int $consumableId - * @see ConsumablesController::postEdit() method that stores the form data. - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function edit($consumableId = null) - { - if ($item = Consumable::find($consumableId)) { - $this->authorize($item); - $category_type = 'consumable'; - return view('consumables/edit', compact('item'))->with('category_type', $category_type); - } - - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); - - } - - - /** - * Returns a form view to edit a consumable. - * - * @author [A. Gianotto] [] - * @param int $consumableId - * @see ConsumablesController::getEdit() method that stores the form data. - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function update(ImageUploadRequest $request, $consumableId = null) - { - if (is_null($consumable = Consumable::find($consumableId))) { - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); - } - - $this->authorize($consumable); - - $consumable->name = $request->input('name'); - $consumable->category_id = $request->input('category_id'); - $consumable->location_id = $request->input('location_id'); - $consumable->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $consumable->order_number = $request->input('order_number'); - $consumable->min_amt = $request->input('min_amt'); - $consumable->manufacturer_id = $request->input('manufacturer_id'); - $consumable->model_number = $request->input('model_number'); - $consumable->item_no = $request->input('item_no'); - $consumable->purchase_date = $request->input('purchase_date'); - $consumable->purchase_cost = Helper::ParseFloat(Input::get('purchase_cost')); - $consumable->qty = Helper::ParseFloat(Input::get('qty')); - - if ($request->file('image')) { - $image = $request->file('image'); - $file_name = str_random(25).".".$image->getClientOriginalExtension(); - $path = public_path('uploads/consumables/'.$file_name); - Image::make($image->getRealPath())->resize(800, null, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path); - $consumable->image = $file_name; - } elseif ($request->input('image_delete')=='1') { - $consumable->image = null; - } - - if ($consumable->save()) { - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.update.success')); - } - return redirect()->back()->withInput()->withErrors($consumable->getErrors()); - } - - /** - * Delete a consumable. - * - * @author [A. Gianotto] [] - * @param int $consumableId - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy($consumableId) - { - if (is_null($consumable = Consumable::find($consumableId))) { - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found')); - } - $this->authorize($consumable); - $consumable->delete(); - // Redirect to the locations management page - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.delete.success')); - } - - /** - * Return a view to display component information. - * - * @author [A. Gianotto] [] - * @see ConsumablesController::getDataView() method that generates the JSON response - * @since [v1.0] - * @param int $consumableId - * @return \Illuminate\Contracts\View\View - */ - public function show($consumableId = null) - { - $consumable = Consumable::find($consumableId); - $this->authorize($consumable); - if (isset($consumable->id)) { - return view('consumables/view', compact('consumable')); - } - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); - } - - /** - * Return a view to checkout a consumable to a user. - * - * @author [A. Gianotto] [] - * @see ConsumablesController::postCheckout() method that stores the data. - * @since [v1.0] - * @param int $consumableId - * @return \Illuminate\Contracts\View\View - */ - public function getCheckout($consumableId) - { - if (is_null($consumable = Consumable::find($consumableId))) { - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); - } - $this->authorize('checkout', $consumable); - return view('consumables/checkout', compact('consumable')); - } - - /** - * Saves the checkout information - * - * @author [A. Gianotto] [] - * @see ConsumablesController::getCheckout() method that returns the form. - * @since [v1.0] - * @param int $consumableId - * @return \Illuminate\Http\RedirectResponse - */ - public function postCheckout($consumableId) - { - if (is_null($consumable = Consumable::find($consumableId))) { - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found')); - } - - $this->authorize('checkout', $consumable); - - $admin_user = Auth::user(); - $assigned_to = e(Input::get('assigned_to')); - - // Check if the user exists - if (is_null($user = User::find($assigned_to))) { - // Redirect to the consumable management page with error - return redirect()->route('checkout/consumable', $consumable)->with('error', trans('admin/consumables/message.checkout.user_does_not_exist')); - } - - // Update the consumable data - $consumable->assigned_to = e(Input::get('assigned_to')); - - $consumable->users()->attach($consumable->id, [ - 'consumable_id' => $consumable->id, - 'user_id' => $admin_user->id, - 'assigned_to' => e(Input::get('assigned_to')) - ]); - - $logaction = $consumable->logCheckout(e(Input::get('note')), $user); - $data['log_id'] = $logaction->id; - $data['eula'] = $consumable->getEula(); - $data['first_name'] = $user->first_name; - $data['item_name'] = $consumable->name; - $data['checkout_date'] = $logaction->created_at; - $data['note'] = $logaction->note; - $data['require_acceptance'] = $consumable->requireAcceptance(); - - - // Redirect to the new consumable page - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success')); - - } - -} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 496e8f50fb..14f56d0d05 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -22,10 +22,10 @@ namespace App\Http\Controllers; use Auth; -use Illuminate\Foundation\Bus\DispatchesJobs; -use Illuminate\Routing\Controller as BaseController; -use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Illuminate\Foundation\Bus\DispatchesJobs; +use Illuminate\Foundation\Validation\ValidatesRequests; +use Illuminate\Routing\Controller as BaseController; abstract class Controller extends BaseController { diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index 62f2cf32f7..e58e00c193 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -1,19 +1,12 @@ ] - * @since [v1.8] - * @return View - */ + * Returns a view with a listing of custom fields. + * + * @author [Brady Wetherington] [] + * @since [v1.8] + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function index() { $this->authorize('view', CustomField::class); $fieldsets = CustomFieldset::with("fields", "models")->get(); $fields = CustomField::with("fieldset")->get(); + return view("custom_fields.index")->with("custom_fieldsets", $fieldsets)->with("custom_fields", $fields); } - - - /** - * Returns a view with a form to create a new custom field. - * - * @see CustomFieldsController::storeField() - * @author [Brady Wetherington] [] - * @since [v1.8] - * @return View - */ + * Returns a view with a form to create a new custom field. + * + * @see CustomFieldsController::storeField() + * @author [Brady Wetherington] [] + * @since [v1.8] + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function create() { $this->authorize('create', CustomField::class); - return view("custom_fields.fields.edit")->with('field', new CustomField()); + return view("custom_fields.fields.edit",[ + 'predefinedFormats' => Helper::predefined_formats(), + 'customFormat' => '' + ])->with('field', new CustomField()); } /** - * Validates and stores a new custom field. - * - * @see CustomFieldsController::createField() - * @author [Brady Wetherington] [] - * @since [v1.8] - * @return Redirect - */ + * Validates and stores a new custom field. + * + * @see CustomFieldsController::createField() + * @author [Brady Wetherington] [] + * @since [v1.8] + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function store(CustomFieldRequest $request) { $this->authorize('create', CustomField::class); @@ -83,22 +80,24 @@ class CustomFieldsController extends Controller "field_values" => $request->get("field_values"), "field_encrypted" => $request->get("field_encrypted", 0), "show_in_email" => $request->get("show_in_email", 0), - "user_id" => Auth::user()->id + "user_id" => Auth::id() ]); - if ($request->has("custom_format")) { + if ($request->filled("custom_format")) { $field->format = e($request->get("custom_format")); } else { $field->format = e($request->get("format")); } if ($field->save()) { + return redirect()->route("fields.index")->with("success", trans('admin/custom_fields/message.field.create.success')); - } else { - return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.field.create.error')); } + return redirect()->back()->withInput() + ->with('error', trans('admin/custom_fields/message.field.create.error')); + } @@ -108,6 +107,7 @@ class CustomFieldsController extends Controller * @author [A. Gianotto] [] * @since [v3.0] * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function deleteFieldFromFieldset($field_id, $fieldset_id) { @@ -116,19 +116,21 @@ class CustomFieldsController extends Controller $this->authorize('update', $field); if ($field->fieldset()->detach($fieldset_id)) { - return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id])->with("success", trans('admin/custom_fields/message.field.delete.success')); + return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id]) + ->with("success", trans('admin/custom_fields/message.field.delete.success')); } return redirect()->back()->withErrors(['message' => "Field is in-use"]); } /** - * Delete a custom field. - * - * @author [Brady Wetherington] [] - * @since [v1.8] - * @return Redirect - */ + * Delete a custom field. + * + * @author [Brady Wetherington] [] + * @since [v1.8] + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function destroy($field_id) { $field = CustomField::find($field_id); @@ -137,56 +139,66 @@ class CustomFieldsController extends Controller if ($field->fieldset->count()>0) { return redirect()->back()->withErrors(['message' => "Field is in-use"]); - } else { - $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 a view to edit a custom field - * - * @author [A. Gianotto] [] - * @param int $id - * @since [v4.0] - * @return View - */ + * Return a view to edit a custom field + * + * @author [A. Gianotto] [] + * @param int $id + * @since [v4.0] + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function edit($id) { $field = CustomField::find($id); $this->authorize('update', $field); - return view("custom_fields.fields.edit")->with('field', $field); + $customFormat = ''; + if((stripos($field->format, 'regex') === 0) && ($field->format !== CustomField::PREDEFINED_FORMATS['MAC'])) { + $customFormat = $field->format; + } + + return view("custom_fields.fields.edit",[ + 'field' => $field, + 'customFormat' => $customFormat, + 'predefinedFormats' => Helper::predefined_formats() + ]); } /** - * Store the updated field - * - * @todo Allow encrypting/decrypting if encryption status changes - * - * @author [A. Gianotto] [] - * @param int $id - * @since [v4.0] - * @return Redirect - */ + * Store the updated field + * + * @todo Allow encrypting/decrypting if encryption status changes + * + * @author [A. Gianotto] [] + * @param int $id + * @since [v4.0] + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function update(CustomFieldRequest $request, $id) { $field = CustomField::find($id); - + $this->authorize('update', $field); - $field->name = e($request->get("name")); - $field->element = e($request->get("element")); - $field->field_values = e($request->get("field_values")); - $field->user_id = Auth::user()->id; - $field->help_text = $request->get("help_text"); + $field->name = e($request->get("name")); + $field->element = e($request->get("element")); + $field->field_values = e($request->get("field_values")); + $field->user_id = Auth::id(); + $field->help_text = $request->get("help_text"); $field->show_in_email = $request->get("show_in_email", 0); - if (!in_array(Input::get('format'), array_keys(CustomField::$PredefinedFormats))) { + if ($request->get('format') == 'CUSTOM REGEX') { $field->format = e($request->get("custom_format")); } else { $field->format = e($request->get("format")); diff --git a/app/Http/Controllers/CustomFieldsetsController.php b/app/Http/Controllers/CustomFieldsetsController.php index f8b96e81c7..f484931325 100644 --- a/app/Http/Controllers/CustomFieldsetsController.php +++ b/app/Http/Controllers/CustomFieldsetsController.php @@ -1,17 +1,14 @@ ] - * @param int $id - * @since [v1.8] - * @return View - */ + /** + * Validates and stores a new custom field. + * + * @author [Brady Wetherington] [] + * @param int $id + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v1.8] + */ public function show($id) { - $cfset = CustomFieldset::with('fields')->where('id', '=', $id)->orderBy('id', 'ASC')->first(); + $cfset = CustomFieldset::with('fields') + ->where('id', '=', $id)->orderBy('id', 'ASC')->first(); $this->authorize('view', $cfset); if ($cfset) { $custom_fields_list = ["" => "Add New Field to Fieldset"] + CustomField::pluck("name", "id")->toArray(); + $maxid = 0; foreach ($cfset->fields as $field) { if ($field->pivot->order > $maxid) { @@ -56,18 +56,20 @@ class CustomFieldsetsController extends Controller return view("custom_fields.fieldsets.view")->with("custom_fieldset", $cfset)->with("maxid", $maxid+1)->with("custom_fields_list", $custom_fields_list); } - return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.does_not_exist')); + return redirect()->route("fields.index") + ->with("error", trans('admin/custom_fields/message.fieldset.does_not_exist')); } /** - * Returns a view with a form for creating a new custom fieldset. - * - * @author [Brady Wetherington] [] - * @since [v1.8] - * @return View - */ + * Returns a view with a form for creating a new custom fieldset. + * + * @author [Brady Wetherington] [] + * @since [v1.8] + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function create() { $this->authorize('create', CustomFieldset::class); @@ -77,29 +79,30 @@ class CustomFieldsetsController extends Controller /** - * Validates and stores a new custom fieldset. - * - * @author [Brady Wetherington] [] - * @since [v1.8] - * @return Redirect - */ + * Validates and stores a new custom fieldset. + * + * @author [Brady Wetherington] [] + * @since [v1.8] + * @param Request $request + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function store(Request $request) { $this->authorize('create', CustomFieldset::class); - $cfset = new CustomFieldset( - [ + $cfset = new CustomFieldset([ "name" => e($request->get("name")), - "user_id" => Auth::user()->id] - ); + "user_id" => Auth::user()->id + ]); - $validator = Validator::make(Input::all(), $cfset->rules); + $validator = Validator::make($request->all(), $cfset->rules); if ($validator->passes()) { $cfset->save(); - return redirect()->route("fieldsets.show", [$cfset->id])->with('success', trans('admin/custom_fields/message.fieldset.create.success')); - } else { - return redirect()->back()->withInput()->withErrors($validator); + return redirect()->route("fieldsets.show", [$cfset->id]) + ->with('success', trans('admin/custom_fields/message.fieldset.create.success')); } + return redirect()->back()->withInput()->withErrors($validator); } @@ -136,13 +139,14 @@ class CustomFieldsetsController extends Controller /** - * Validates a custom fieldset and then deletes if it has no models associated. - * - * @author [Brady Wetherington] [] - * @param int $id - * @since [v1.8] - * @return View - */ + * Validates a custom fieldset and then deletes if it has no models associated. + * + * @author [Brady Wetherington] [] + * @param int $id + * @since [v1.8] + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function destroy($id) { $fieldset = CustomFieldset::find($id); @@ -154,9 +158,8 @@ class CustomFieldsetsController extends Controller if ($models->count() == 0) { $fieldset->delete(); return redirect()->route("fields.index")->with("success", trans('admin/custom_fields/message.fieldset.delete.success')); - } else { - return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.delete.in_use')); } + return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.delete.in_use')); } return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.does_not_exist')); @@ -186,7 +189,7 @@ class CustomFieldsetsController extends Controller } } - $results = $set->fields()->attach(Input::get('field_id'), ["required" => ($request->input('required') == "on"),"order" => $request->input('order', 1)]); + $results = $set->fields()->attach($request->input('field_id'), ["required" => ($request->input('required') == "on"),"order" => $request->input('order', 1)]); return redirect()->route("fieldsets.show", [$id])->with("success", trans('admin/custom_fields/message.field.create.assoc_success')); } @@ -233,5 +236,4 @@ class CustomFieldsetsController extends Controller ->with("success", trans('Field successfully set to optional')); } - } diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 0fbdcf6c89..e6ad988c45 100755 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -2,12 +2,8 @@ namespace App\Http\Controllers; use App\Http\Controllers\AdminController; -use App\Models\Actionlog; -use View; use Auth; -use Redirect; -use App\Models\Asset; -use App\Models\Company; +use View; /** * This controller handles all actions related to the Admin Dashboard diff --git a/app/Http/Controllers/DepartmentsController.php b/app/Http/Controllers/DepartmentsController.php index c0788ee65a..b0d7768b0f 100644 --- a/app/Http/Controllers/DepartmentsController.php +++ b/app/Http/Controllers/DepartmentsController.php @@ -2,12 +2,11 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; -use App\Models\Department; -use App\Helpers\Helper; -use Auth; -use Image; use App\Http\Requests\ImageUploadRequest; +use App\Models\Department; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Storage; class DepartmentsController extends Controller { @@ -24,7 +23,9 @@ class DepartmentsController extends Controller * @author [A. Gianotto] [] * @see AssetController::getDatatable() method that generates the JSON response * @since [v4.0] - * @return View + * @param Request $request + * @return \Illuminate\Support\Facades\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index(Request $request) { @@ -42,8 +43,9 @@ class DepartmentsController extends Controller * * @author [A. Gianotto] [] * @since [v4.0] - * @param \Illuminate\Http\Request $request + * @param ImageUploadRequest $request * @return \Illuminate\Http\Response + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(ImageUploadRequest $request) { @@ -53,7 +55,7 @@ class DepartmentsController extends Controller $department->user_id = Auth::user()->id; $department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null); - $department = $request->handleImages($department,600, public_path().'/uploads/departments'); + $department = $request->handleImages($department); if ($department->save()) { return redirect()->route("departments.index")->with('success', trans('admin/departments/message.create.success')); @@ -69,6 +71,7 @@ class DepartmentsController extends Controller * @param int $id * @since [v4.0] * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function show($id) { @@ -90,6 +93,7 @@ class DepartmentsController extends Controller * @see DepartmentsController::postCreate() method that validates and stores the data * @since [v4.0] * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create() { @@ -106,6 +110,7 @@ class DepartmentsController extends Controller * @param int $locationId * @since [v4.0] * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($id) { @@ -119,23 +124,32 @@ class DepartmentsController extends Controller return redirect()->to(route('departments.index'))->with('error', trans('admin/departments/message.assoc_users')); } + if ($department->image) { + try { + Storage::disk('public')->delete('departments'.'/'.$department->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } $department->delete(); + return redirect()->back()->with('success', trans('admin/departments/message.delete.success')); } /** - * Makes a form view to edit location information. + * Makes a form view to edit Department information. * * @author [A. Gianotto] [] * @see LocationsController::postCreate() method that validates and stores - * @param int $locationId + * @param int $departmentId * @since [v1.0] * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function edit($id = null) + public function edit($departmentId = null) { - if (is_null($item = Department::find($id))) { + if (is_null($item = Department::find($departmentId))) { return redirect()->back()->with('error', trans('admin/locations/message.does_not_exist')); } @@ -155,8 +169,8 @@ class DepartmentsController extends Controller $department->fill($request->all()); $department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null); - $department = $request->handleImages($department,600, public_path().'/uploads/departments'); - + $department = $request->handleImages($department); + if ($department->save()) { return redirect()->route("departments.index")->with('success', trans('admin/departments/message.update.success')); } diff --git a/app/Http/Controllers/DepreciationsController.php b/app/Http/Controllers/DepreciationsController.php index d9f84415ee..d7177829ea 100755 --- a/app/Http/Controllers/DepreciationsController.php +++ b/app/Http/Controllers/DepreciationsController.php @@ -1,16 +1,9 @@ find($depreciationId))) { return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.not_found')); } $this->authorize('delete', $depreciation); - if ($depreciation->has_models() > 0) { + if ($depreciation->models_count > 0) { // Redirect to the asset management page return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.assoc_users')); } @@ -175,6 +174,7 @@ class DepreciationsController extends Controller * @param int $depreciationId * @since [v1.0] * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function show($id) { diff --git a/app/Http/Controllers/GroupsController.php b/app/Http/Controllers/GroupsController.php index e03847cd2e..370c8eba52 100755 --- a/app/Http/Controllers/GroupsController.php +++ b/app/Http/Controllers/GroupsController.php @@ -1,15 +1,10 @@ old('permissions', $groupPermissions); // Show the page return view('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions'))->with('group', $group); @@ -62,12 +57,12 @@ class GroupsController extends Controller * @since [v1.0] * @return \Illuminate\Http\RedirectResponse */ - public function store() + public function store(Request $request) { // create a new group instance $group = new Group(); - $group->name = e(Input::get('name')); - $group->permissions = json_encode(Input::get('permission')); + $group->name = $request->input('name'); + $group->permissions = json_encode($request->input('permission')); if ($group->save()) { return redirect()->route("groups.index")->with('success', trans('admin/groups/message.success.create')); @@ -107,14 +102,13 @@ class GroupsController extends Controller * @since [v1.0] * @return \Illuminate\Http\RedirectResponse */ - public function update($id = null) + public function update(Request $request, $id = null) { - $permissions = config('permissions'); if (!$group = Group::find($id)) { return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id'))); } - $group->name = e(Input::get('name')); - $group->permissions = json_encode(Input::get('permission')); + $group->name = $request->input('name'); + $group->permissions = json_encode($request->input('permission')); if (!config('app.lock_passwords')) { if ($group->save()) { @@ -126,13 +120,14 @@ class GroupsController extends Controller } /** - * Validates and deletes the User Group. - * - * @author [A. Gianotto] [] - * @param int $locationId - * @since [v4.0.11] + * @param $id * @return \Illuminate\Contracts\View\View + * @since [v4.0.11] */ public function show($id) { diff --git a/app/Http/Controllers/ImportsController.php b/app/Http/Controllers/ImportsController.php index c3bd66245a..46954303c5 100644 --- a/app/Http/Controllers/ImportsController.php +++ b/app/Http/Controllers/ImportsController.php @@ -3,18 +3,19 @@ namespace App\Http\Controllers; use App\Http\Transformers\ImportsTransformer; -use App\Models\Import; -use Illuminate\Http\Request; use App\Models\Asset; - +use App\Models\Import; class ImportsController extends Controller { + /** + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ public function index() { $this->authorize('import'); - $imports = Import::latest()->get(); - $imports = (new ImportsTransformer)->transformImports($imports); + $imports = (new ImportsTransformer)->transformImports(Import::latest()->get()); return view('importer/import')->with('imports', $imports); } } diff --git a/app/Http/Controllers/Kits/CheckoutKitController.php b/app/Http/Controllers/Kits/CheckoutKitController.php new file mode 100644 index 0000000000..0d99560751 --- /dev/null +++ b/app/Http/Controllers/Kits/CheckoutKitController.php @@ -0,0 +1,71 @@ +] + */ +class CheckoutKitController extends Controller +{ + + public $kitService; + use CheckInOutRequest; + + public function __construct(PredefinedKitCheckoutService $kitService) + { + $this->kitService = $kitService; + } + + /** + * Show Bulk Checkout Page + * + * @author [D. Minaev.] [] + * @return View View to checkout + */ + public function showCheckout($kit_id) + { + $this->authorize('checkout', Asset::class); + + $kit = PredefinedKit::findOrFail($kit_id); + return view('kits/checkout')->with('kit', $kit); + } + + /** + * Validate and process the new Predefined Kit data. + * + * @author [D. Minaev.] [] + * @return Redirect + */ + public function store(Request $request, $kit_id) + { + $user_id = e($request->get('user_id')); + if (is_null($user = User::find($user_id))) { + return redirect()->back()->with('error', trans('admin/users/message.user_not_found')); + } + + $kit = new PredefinedKit(); + $kit->id = $kit_id; + + $checkout_result = $this->kitService->checkout($request, $kit, $user); + if (Arr::has($checkout_result, 'errors') && count($checkout_result['errors']) > 0 ) { + return redirect()->back()->with('error', 'Checkout error')->with('error_messages', $checkout_result['errors']); // TODO: trans + } + return redirect()->back()->with('success', 'Checkout was successful') + ->with('assets', Arr::get($checkout_result, 'assets', null)) + ->with('accessories', Arr::get($checkout_result, 'accessories', null)) + ->with('consumables', Arr::get($checkout_result, 'consumables', null)); // TODO: trans + + } +} diff --git a/app/Http/Controllers/Kits/PredefinedKitsController.php b/app/Http/Controllers/Kits/PredefinedKitsController.php new file mode 100644 index 0000000000..79c76f887d --- /dev/null +++ b/app/Http/Controllers/Kits/PredefinedKitsController.php @@ -0,0 +1,469 @@ +] + */ +class PredefinedKitsController extends Controller +{ + /** + * @author [D. Minaev] [] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('index', PredefinedKit::class); + return view('kits/index'); + } + + /** + * Returns a form view to create a new kit. + * + * @author [D. Minaev] [] + * @throws \Illuminate\Auth\Access\AuthorizationException + * @return mixed + */ + public function create() + { + $this->authorize('create', PredefinedKit::class); + return view('kits/create')->with('item', new PredefinedKit); + } + + /** + * Validate and process the new Predefined Kit data. + * + * @author [D. Minaev] [] + * @return Redirect + */ + public function store(ImageUploadRequest $request) + { + $this->authorize('create', PredefinedKit::class); + // Create a new Predefined Kit + $kit = new PredefinedKit; + $kit->name = $request->input('name'); + + if (!$kit->save()) { + return redirect()->back()->withInput()->withErrors($kit->getErrors()); + } + $success = $kit->save(); + if (!$success) { + return redirect()->back()->withInput()->withErrors($kit->getErrors()); + } + return redirect()->route("kits.index")->with('success', 'Kit was successfully created.'); // TODO: trans() + } + + /** + * Returns a view containing the Predefined Kit edit form. + * + * @author [D. Minaev] [] + * @since [v1.0] + * @param int $kit_id + * @return View + */ + public function edit($kit_id=null) + { + $this->authorize('update', PredefinedKit::class); + if ($kit = PredefinedKit::find($kit_id)) { + return view('kits/edit') + ->with('item', $kit) + ->with('models', $kit->models) + ->with('licenses', $kit->licenses); + } + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + + /** + * Validates and processes form data from the edit + * Predefined Kit form based on the kit ID passed. + * + * @author [D. Minaev] [] + * @since [v1.0] + * @param int $kit_id + * @return Redirect + */ + public function update(ImageUploadRequest $request, $kit_id=null) + { + $this->authorize('update', PredefinedKit::class); + // Check if the kit exists + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + $kit->name = $request->input('name'); + + if ($kit->save()) { + return redirect()->route("kits.index")->with('success', 'Kit was successfully updated'); // TODO: trans + } + return redirect()->back()->withInput()->withErrors($kit->getErrors()); + } + + /** + * Validate and delete the given Predefined Kit. + * Also delete all contained helping items + * + * @author [D. Minaev] [] + * @since [v1.0] + * @param int $kit_id + * @return Redirect + */ + public function destroy($kit_id) + { + $this->authorize('delete', PredefinedKit::class); + // Check if the kit exists + if (is_null($kit = PredefinedKit::find($kit_id))) { + return redirect()->route('kits.index')->with('error', 'Kit not found'); // TODO: trans + } + + // Delete childs + $kit->models()->detach(); + $kit->licenses()->detach(); + $kit->consumables()->detach(); + $kit->accessories()->detach(); + // Delete the kit + $kit->delete(); + + // Redirect to the kit management page + return redirect()->route('kits.index')->with('success', 'Kit was successfully deleted'); // TODO: trans + } + + /** + * Get the kit information to present to the kit view page + * + * @author [D. Minaev] [] + * @since [v1.0] + * @param int $modelId + * @return View + */ + public function show($kit_id=null) + { + return $this->edit($kit_id); + } + + + /** + * Returns a view containing the Predefined Kit edit form. + * + * @author [D. Minaev] [] + * @param int $kit_id + * @return View + */ + public function editModel($kit_id, $model_id) + { + $this->authorize('update', PredefinedKit::class); + if (($kit = PredefinedKit::find($kit_id)) + && ($model = $kit->models()->find($model_id))) { + + return view('kits/model-edit', [ + 'kit' => $kit, + 'model' => $model, + 'item' => $model->pivot + ]); + } + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + /** + * Get the kit information to present to the kit view page + * + * @author [D. Minaev] [] + * @param int $modelId + * @return View + */ + public function updateModel(Request $request, $kit_id, $model_id) + { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeModelRules($model_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->models()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->model_id = $request->input('model_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'Model updated successfully.'); // TODO: trans + } + + /** + * Remove the model from set + * + * @author [D. Minaev] [] + * @param int $modelId + * @return View + */ + public function detachModel($kit_id, $model_id) + { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->models()->detach($model_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'Model was successfully detached'); // TODO: trans + } + + /** + * Returns a view containing attached license edit form. + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $license_id + * @return View + */ + public function editLicense($kit_id, $license_id) + { + $this->authorize('update', PredefinedKit::class); + if (!($kit = PredefinedKit::find($kit_id))) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if (!($license = $kit->licenses()->find($license_id))) { + return redirect()->route('kits.index')->with('error', 'License does not exist'); // TODO: trans + } + + return view('kits/license-edit', [ + 'kit' => $kit, + 'license' => $license, + 'item' => $license->pivot + ]); + } + + /** + * Update attached licese + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $license_id + * @return View + */ + public function updateLicense(Request $request, $kit_id, $license_id) + { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeLicenseRules($license_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->licenses()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->license_id = $request->input('license_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'License updated successfully.'); // TODO: trans + } + + /** + * Remove the license from set + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $license_id + * @return View + */ + public function detachLicense($kit_id, $license_id) + { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->licenses()->detach($license_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'License was successfully detached'); // TODO: trans + } + + + /** + * Returns a view containing attached accessory edit form. + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $accessoryId + * @return View + */ + public function editAccessory($kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + if (!($kit = PredefinedKit::find($kit_id))) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if (!($accessory = $kit->accessories()->find($accessory_id))) { + return redirect()->route('kits.index')->with('error', 'Accessory does not exist'); // TODO: trans + } + + return view('kits/accessory-edit', [ + 'kit' => $kit, + 'accessory' => $accessory, + 'item' => $accessory->pivot + ]); + } + + /** + * Update attached accessory + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $accessory_id + * @return View + */ + public function updateAccessory(Request $request, $kit_id, $accessory_id) + { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeAccessoryRules($accessory_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->accessories()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->accessory_id = $request->input('accessory_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'Accessory updated successfully.'); // TODO: trans + } + + /** + * Remove the accessory from set + * + * @author [D. Minaev] [] + * @param int $accessory_id + * @return View + */ + public function detachAccessory($kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->accessories()->detach($accessory_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'Accessory was successfully detached'); // TODO: trans + } + + /** + * Returns a view containing attached consumable edit form. + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $consumable_id + * @return View + */ + public function editConsumable($kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + if (!($kit = PredefinedKit::find($kit_id))) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if (!($consumable = $kit->consumables()->find($consumable_id))) { + return redirect()->route('kits.index')->with('error', 'Consumable does not exist'); // TODO: trans + } + + return view('kits/consumable-edit', [ + 'kit' => $kit, + 'consumable' => $consumable, + 'item' => $consumable->pivot + ]); + } + + /** + * Update attached consumable + * + * @author [D. Minaev] [] + * @param int $kit_id + * @param int $consumableId + * @return View + */ + public function updateConsumable(Request $request, $kit_id, $consumable_id) + { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeConsumableRules($consumable_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->consumables()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->consumable_id = $request->input('consumable_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'Consumable updated successfully.'); // TODO: trans + } + + /** + * Remove the consumable from set + * + * @author [D. Minaev] [] + * @param int $consumable_id + * @return View + */ + public function detachConsumable($kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->consumables()->detach($consumable_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'Consumable was successfully detached'); // TODO: trans + } +} diff --git a/app/Http/Controllers/Licenses/LicenseCheckinController.php b/app/Http/Controllers/Licenses/LicenseCheckinController.php new file mode 100644 index 0000000000..a5be968cad --- /dev/null +++ b/app/Http/Controllers/Licenses/LicenseCheckinController.php @@ -0,0 +1,104 @@ +] + * @since [v1.0] + * @param int $seatId + * @param string $backTo + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($seatId = null, $backTo = null) + { + // Check if the asset exists + if (is_null($licenseSeat = LicenseSeat::find($seatId)) || is_null($license = License::find($licenseSeat->license_id))) { + // Redirect to the asset management page with error + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); + } + + $this->authorize('checkout', $license); + return view('licenses/checkin', compact('licenseSeat'))->with('backto', $backTo); + } + + + /** + * Validates and stores the license checkin action. + * + * @author [A. Gianotto] [] + * @see LicenseCheckinController::create() method that provides the form view + * @since [v1.0] + * @param int $seatId + * @param string $backTo + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request, $seatId = null, $backTo = null) + { + // Check if the asset exists + if (is_null($licenseSeat = LicenseSeat::find($seatId))) { + // Redirect to the asset management page with error + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); + } + + $license = License::find($licenseSeat->license_id); + $this->authorize('checkout', $license); + + if (!$license->reassignable) { + // Not allowed to checkin + Session::flash('error', 'License not reassignable.'); + return redirect()->back()->withInput(); + } + + // Declare the rules for the form validation + $rules = [ + 'note' => 'string|nullable', + ]; + + // Create a new validator instance from our validation rules + $validator = Validator::make($request->all(), $rules); + + // If validation fails, we'll exit the operation now. + if ($validator->fails()) { + // Ooops.. something went wrong + return redirect()->back()->withInput()->withErrors($validator); + } + $return_to = User::find($licenseSeat->assigned_to); + + // Update the asset data + $licenseSeat->assigned_to = null; + $licenseSeat->asset_id = null; + + // Was the asset updated? + if ($licenseSeat->save()) { + + event(new CheckoutableCheckedIn($licenseSeat, $return_to, Auth::user(), $request->input('note'))); + + if ($backTo=='user') { + return redirect()->route("users.show", $return_to->id)->with('success', trans('admin/licenses/message.checkin.success')); + } + return redirect()->route("licenses.show", $licenseSeat->license_id)->with('success', trans('admin/licenses/message.checkin.success')); + } + + // Redirect to the license page with error + return redirect()->route("licenses.index")->with('error', trans('admin/licenses/message.checkin.error')); + } + +} diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php new file mode 100644 index 0000000000..8edbc2e664 --- /dev/null +++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php @@ -0,0 +1,128 @@ +] + * @since [v1.0] + * @param $licenseId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create($licenseId) + { + // Check that the license is valid + if ($license = License::find($licenseId)) { + + // If the license is valid, check that there is an available seat + if ($license->avail_seats_count < 1) { + return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); + } + } + + $this->authorize('checkout', $license); + return view('licenses/checkout', compact('license')); + } + + + /** + * Validates and stores the license checkout action. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param LicenseCheckoutRequest $request + * @param $licenseId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + + public function store(LicenseCheckoutRequest $request, $licenseId, $seatId = null) + { + if (!$license = License::find($licenseId)) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); + } + + $this->authorize('checkout', $license); + + $licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId); + $licenseSeat->user_id = Auth::id(); + + $checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type')); + if ($this->$checkoutMethod($licenseSeat)) { + return redirect()->route("licenses.index")->with('success', trans('admin/licenses/message.checkout.success')); + } + + return redirect()->route("licenses.index")->with('error', trans('Something went wrong handling this checkout.')); + } + + protected function findLicenseSeatToCheckout($license, $seatId) + { + $licenseSeat = LicenseSeat::find($seatId) ?? $license->freeSeat(); + + if (!$licenseSeat) { + if ($seatId) { + return redirect()->route('licenses.index')->with('error', 'This Seat is not available for checkout.'); + } + return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); + } + + if(!$licenseSeat->license->is($license)) { + return redirect()->route('licenses.index')->with('error', 'The license seat provided does not match the license.'); + } + + return $licenseSeat; + } + + protected function checkoutToAsset($licenseSeat) + { + if (is_null($target = Asset::find(request('asset_id')))) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist')); + } + $licenseSeat->asset_id = request('asset_id'); + + // Override asset's assigned user if available + if ($target->checkedOutToUser()) { + $licenseSeat->assigned_to = $target->assigned_to; + } + if ($licenseSeat->save()) { + + event(new CheckoutableCheckedOut($licenseSeat, $target, Auth::user(), request('note'))); + + return true; + } + return false; + } + + protected function checkoutToUser($licenseSeat) + { + // Fetch the target and set the license user + if (is_null($target = User::find(request('assigned_to')))) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist')); + } + $licenseSeat->assigned_to = request('assigned_to'); + + if ($licenseSeat->save()) { + + event(new CheckoutableCheckedOut($licenseSeat, $target, Auth::user(), request('note'))); + + return true; + } + return false; + } +} diff --git a/app/Http/Controllers/Licenses/LicenseFilesController.php b/app/Http/Controllers/Licenses/LicenseFilesController.php new file mode 100644 index 0000000000..cfa11609ff --- /dev/null +++ b/app/Http/Controllers/Licenses/LicenseFilesController.php @@ -0,0 +1,170 @@ +] + * @since [v1.0] + * @param AssetFileRequest $request + * @param int $licenseId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(AssetFileRequest $request, $licenseId = null) + { + $license = License::find($licenseId); + + if (isset($license->id)) { + $this->authorize('update', $license); + + if ($request->hasFile('file')) { + + if (!Storage::exists('private_uploads/licenses')) Storage::makeDirectory('private_uploads/licenses', 775); + + $upload_success = false; + foreach ($request->file('file') as $file) { + + $file_name = 'license-'.date('Y-m-d-His').'-'.$file->getBasename().'.'.$file->getClientOriginalExtension(); + + + $upload_success = $file->storeAs('private_uploads/licenses', $file_name); + // $upload_success = $file->storeAs('private_uploads/licenses/'.$file_name, $file); + + //Log the upload to the log + $license->logUpload($file_name, e($request->input('notes'))); + } + + // This being called from a modal seems to confuse redirect()->back() + // It thinks we should go to the dashboard. As this is only used + // from the modal at present, hardcode the redirect. Longterm + // maybe we evaluate something else. + if ($upload_success) { + return redirect()->route('licenses.show', $license->id)->with('success', trans('admin/licenses/message.upload.success')); + } + return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.error')); + } + return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.nofiles')); + } + // Prepare the error message + return redirect()->route('licenses.index') + ->with('error', trans('admin/licenses/message.does_not_exist')); + } + + + /** + * Deletes the selected license file. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $licenseId + * @param int $fileId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($licenseId = null, $fileId = null) + { + $license = License::find($licenseId); + + // the asset is valid + if (isset($license->id)) { + $this->authorize('update', $license); + $log = Actionlog::find($fileId); + + // Remove the file if one exists + if (Storage::exists('licenses/'.$log->filename)) { + try { + Storage::delete('licenses/'.$log->filename); + } catch (\Exception $e) { + \Log::debug($e); + } + } + + $log->delete(); + return redirect()->back() + ->with('success', trans('admin/hardware/message.deletefile.success')); + } + + // Redirect to the licence management page + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); + } + + + + /** + * Allows the selected file to be viewed. + * + * @author [A. Gianotto] [] + * @since [v1.4] + * @param int $licenseId + * @param int $fileId + * @return \Symfony\Component\HttpFoundation\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($licenseId = null, $fileId = null, $download = true) + { + + \Log::info('Private filesystem is: '.config('filesystems.default') ); + $license = License::find($licenseId); + + // the license is valid + if (isset($license->id)) { + $this->authorize('view', $license); + + if (!$log = Actionlog::find($fileId)) { + return response('No matching record for that asset/file', 500) + ->header('Content-Type', 'text/plain'); + } + + $file = 'private_uploads/licenses/'.$log->filename; + + + if (Storage::missing($file)) { + \Log::debug('NOT EXISTS for '.$file); + \Log::debug('NOT EXISTS URL should be '.Storage::url($file)); + return response('File '.$file.' ('.Storage::url($file).') not found on server', 404) + ->header('Content-Type', 'text/plain'); + } else { + + // We have to override the URL stuff here, since local defaults in Laravel's Flysystem + // won't work, as they're not accessible via the web + if (config('filesystems.default') == 'local') { + \Log::debug('The private filesystem is local'); + return Response::make(Storage::get($file)); + + } else { + if ($download != 'true') { + if ($contents = file_get_contents(Storage::url($file))) { + return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file))); + } + return JsonResponse::create(["error" => "Failed validation: "], 500); + } + + return Storage::download($file); + } + + } + + + } + return redirect()->route('license.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId])); + + } + + + +} diff --git a/app/Http/Controllers/Licenses/LicensesController.php b/app/Http/Controllers/Licenses/LicensesController.php new file mode 100755 index 0000000000..428dfa4f4f --- /dev/null +++ b/app/Http/Controllers/Licenses/LicensesController.php @@ -0,0 +1,273 @@ +] + * @see LicensesController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('view', License::class); + return view('licenses/index'); + } + + + /** + * Returns a form view that allows an admin to create a new licence. + * + * @author [A. Gianotto] [] + * @see AccessoriesController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create() + { + $this->authorize('create', License::class); + $maintained_list = [ + '' => 'Maintained', + '1' => 'Yes', + '0' => 'No' + ]; + + return view('licenses/edit') + ->with('depreciation_list', Helper::depreciationList()) + ->with('maintained_list', $maintained_list) + ->with('item', new License); + + } + + + /** + * Validates and stores the license form data submitted from the new + * license form. + * + * @author [A. Gianotto] [] + * @see LicensesController::getCreate() method that provides the form view + * @since [v1.0] + * @param Request $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(Request $request) + { + $this->authorize('create', License::class); + // create a new model instance + $license = new License(); + // Save the license data + $license->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $license->depreciation_id = $request->input('depreciation_id'); + $license->expiration_date = $request->input('expiration_date'); + $license->license_email = $request->input('license_email'); + $license->license_name = $request->input('license_name'); + $license->maintained = $request->input('maintained', 0); + $license->manufacturer_id = $request->input('manufacturer_id'); + $license->name = $request->input('name'); + $license->notes = $request->input('notes'); + $license->order_number = $request->input('order_number'); + $license->purchase_cost = $request->input('purchase_cost'); + $license->purchase_date = $request->input('purchase_date'); + $license->purchase_order = $request->input('purchase_order'); + $license->purchase_order = $request->input('purchase_order'); + $license->reassignable = $request->input('reassignable', 0); + $license->seats = $request->input('seats'); + $license->serial = $request->input('serial'); + $license->supplier_id = $request->input('supplier_id'); + $license->category_id = $request->input('category_id'); + $license->termination_date = $request->input('termination_date'); + $license->user_id = Auth::id(); + + if ($license->save()) { + return redirect()->route("licenses.index")->with('success', trans('admin/licenses/message.create.success')); + } + return redirect()->back()->withInput()->withErrors($license->getErrors()); + } + + /** + * Returns a form with existing license data to allow an admin to + * update license information. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $licenseId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit($licenseId = null) + { + if (is_null($item = License::find($licenseId))) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); + } + + $this->authorize('update', $item); + + $maintained_list = [ + '' => 'Maintained', + '1' => 'Yes', + '0' => 'No' + ]; + + return view('licenses/edit', compact('item')) + ->with('depreciation_list', Helper::depreciationList()) + ->with('maintained_list', $maintained_list); + } + + + /** + * Validates and stores the license form data submitted from the edit + * license form. + * + * @author [A. Gianotto] [] + * @see LicensesController::getEdit() method that provides the form view + * @since [v1.0] + * @param Request $request + * @param int $licenseId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function update(Request $request, $licenseId = null) + { + if (is_null($license = License::find($licenseId))) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); + } + + $this->authorize('update', $license); + + $license->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $license->depreciation_id = $request->input('depreciation_id'); + $license->expiration_date = $request->input('expiration_date'); + $license->license_email = $request->input('license_email'); + $license->license_name = $request->input('license_name'); + $license->maintained = $request->input('maintained',0); + $license->name = $request->input('name'); + $license->notes = $request->input('notes'); + $license->order_number = $request->input('order_number'); + $license->purchase_cost = $request->input('purchase_cost'); + $license->purchase_date = $request->input('purchase_date'); + $license->purchase_order = $request->input('purchase_order'); + $license->reassignable = $request->input('reassignable', 0); + $license->serial = $request->input('serial'); + $license->termination_date = $request->input('termination_date'); + $license->seats = e($request->input('seats')); + $license->manufacturer_id = $request->input('manufacturer_id'); + $license->supplier_id = $request->input('supplier_id'); + $license->category_id = $request->input('category_id'); + + if ($license->save()) { + return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success')); + } + // If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php + return redirect()->back()->withInput()->withErrors($license->getErrors()); + } + + /** + * Checks to see whether the selected license can be deleted, and + * if it can, marks it as deleted. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $licenseId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($licenseId) + { + // Check if the license exists + if (is_null($license = License::find($licenseId))) { + // Redirect to the license management page + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); + } + + $this->authorize('delete', $license); + + if ($license->assigned_seats_count == 0) { + // Delete the license and the associated license seats + DB::table('license_seats') + ->where('id', $license->id) + ->update(array('assigned_to' => null,'asset_id' => null)); + + $licenseSeats = $license->licenseseats(); + $licenseSeats->delete(); + $license->delete(); + + // Redirect to the licenses management page + return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.delete.success')); + // Redirect to the license management page + } + // There are still licenses in use. + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.assoc_users')); + + } + + + /** + * Makes the license detail page. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $licenseId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($licenseId = null) + { + + $license = License::with('assignedusers', 'licenseSeats.user', 'licenseSeats.asset')->find($licenseId); + + if ($license) { + $this->authorize('view', $license); + return view('licenses/view', compact('license')); + } + return redirect()->route('licenses.index') + ->with('error', trans('admin/licenses/message.does_not_exist')); + } + + + public function getClone($licenseId = null) + { + if (is_null($license_to_clone = License::find($licenseId))) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); + } + + $this->authorize('create', License::class); + + $maintained_list = [ + '' => 'Maintained', + '1' => 'Yes', + '0' => 'No' + ]; + //clone the orig + $license = clone $license_to_clone; + $license->id = null; + $license->serial = null; + + // Show the page + return view('licenses/edit') + ->with('depreciation_list', Helper::depreciationList()) + ->with('item', $license) + ->with('maintained_list', $maintained_list); + } +} diff --git a/app/Http/Controllers/LicensesController.php b/app/Http/Controllers/LicensesController.php deleted file mode 100755 index 472d6dba3c..0000000000 --- a/app/Http/Controllers/LicensesController.php +++ /dev/null @@ -1,648 +0,0 @@ -] - * @see LicensesController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function index() - { - $this->authorize('view', License::class); - return view('licenses/index'); - } - - - /** - * Returns a form view that allows an admin to create a new licence. - * - * @author [A. Gianotto] [] - * @see AccessoriesController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function create() - { - $this->authorize('create', License::class); - $maintained_list = [ - '' => 'Maintained', - '1' => 'Yes', - '0' => 'No' - ]; - - return view('licenses/edit') - //->with('license_options',$license_options) - ->with('depreciation_list', Helper::depreciationList()) - ->with('maintained_list', $maintained_list) - ->with('item', new License); - - } - - - /** - * Validates and stores the license form data submitted from the new - * license form. - * - * @author [A. Gianotto] [] - * @see LicensesController::getCreate() method that provides the form view - * @since [v1.0] - * @param Request $request - * @return \Illuminate\Http\RedirectResponse - */ - public function store(Request $request) - { - $this->authorize('create', License::class); - // create a new model instance - $license = new License(); - // Save the license data - $license->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $license->depreciation_id = $request->input('depreciation_id'); - $license->expiration_date = $request->input('expiration_date'); - $license->license_email = $request->input('license_email'); - $license->license_name = $request->input('license_name'); - $license->maintained = $request->input('maintained', 0); - $license->manufacturer_id = $request->input('manufacturer_id'); - $license->name = $request->input('name'); - $license->notes = $request->input('notes'); - $license->order_number = $request->input('order_number'); - $license->purchase_cost = $request->input('purchase_cost'); - $license->purchase_date = $request->input('purchase_date'); - $license->purchase_order = $request->input('purchase_order'); - $license->purchase_order = $request->input('purchase_order'); - $license->reassignable = $request->input('reassignable', 0); - $license->seats = $request->input('seats'); - $license->serial = $request->input('serial'); - $license->supplier_id = $request->input('supplier_id'); - $license->category_id = $request->input('category_id'); - $license->termination_date = $request->input('termination_date'); - $license->user_id = Auth::id(); - - if ($license->save()) { - return redirect()->route("licenses.index")->with('success', trans('admin/licenses/message.create.success')); - } - return redirect()->back()->withInput()->withErrors($license->getErrors()); - } - - /** - * Returns a form with existing license data to allow an admin to - * update license information. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @return \Illuminate\Contracts\View\View - */ - public function edit($licenseId = null) - { - if (is_null($item = License::find($licenseId))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - $this->authorize('update', $item); - - $maintained_list = [ - '' => 'Maintained', - '1' => 'Yes', - '0' => 'No' - ]; - - return view('licenses/edit', compact('item')) - ->with('depreciation_list', Helper::depreciationList()) - ->with('maintained_list', $maintained_list); - } - - - /** - * Validates and stores the license form data submitted from the edit - * license form. - * - * @author [A. Gianotto] [] - * @see LicensesController::getEdit() method that provides the form view - * @since [v1.0] - * @param Request $request - * @param int $licenseId - * @return \Illuminate\Http\RedirectResponse - */ - public function update(Request $request, $licenseId = null) - { - if (is_null($license = License::find($licenseId))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - $this->authorize('update', $license); - - $license->company_id = Company::getIdForCurrentUser($request->input('company_id')); - $license->depreciation_id = $request->input('depreciation_id'); - $license->expiration_date = $request->input('expiration_date'); - $license->license_email = $request->input('license_email'); - $license->license_name = $request->input('license_name'); - $license->maintained = $request->input('maintained',0); - $license->name = $request->input('name'); - $license->notes = $request->input('notes'); - $license->order_number = $request->input('order_number'); - $license->purchase_cost = $request->input('purchase_cost'); - $license->purchase_date = $request->input('purchase_date'); - $license->purchase_order = $request->input('purchase_order'); - $license->reassignable = $request->input('reassignable', 0); - if (Gate::allows('viewKeys', $license)) { - $license->serial = $request->input('serial'); - } - $license->termination_date = $request->input('termination_date'); - $license->seats = e($request->input('seats')); - $license->manufacturer_id = $request->input('manufacturer_id'); - $license->supplier_id = $request->input('supplier_id'); - $license->category_id = $request->input('category_id'); - - if ($license->save()) { - return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success')); - } - // If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php - return redirect()->back()->withInput()->withErrors($license->getErrors()); - } - - /** - * Checks to see whether the selected license can be deleted, and - * if it can, marks it as deleted. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy($licenseId) - { - // Check if the license exists - if (is_null($license = License::find($licenseId))) { - // Redirect to the license management page - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } - - $this->authorize('delete', $license); - - if ($license->assigned_seats_count == 0) { - // Delete the license and the associated license seats - DB::table('license_seats') - ->where('id', $license->id) - ->update(array('assigned_to' => null,'asset_id' => null)); - - $licenseSeats = $license->licenseseats(); - $licenseSeats->delete(); - $license->delete(); - - // Redirect to the licenses management page - return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.delete.success')); - // Redirect to the license management page - } - // There are still licenses in use. - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.assoc_users')); - - } - - /** - * Provides the form view for checking out a license to a user. - * Here we pass the license seat ID instead of the license ID, - * because licenses themselves are never checked out to anyone, - * only the seats associated with them. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $seatId - * @return \Illuminate\Contracts\View\View - */ - public function getCheckout($licenceId) - { - - // Check that the license is valid - if ($license = License::where('id',$licenceId)->first()) { - - $this->authorize('checkout', $license); - - // If the license is valid, check that there is an available seat - if ($license->getAvailSeatsCountAttribute() < 1) { - return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); - } - return view('licenses/checkout', compact('license')); - } - - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - - - - } - - - /** - * Validates and stores the license checkout action. - * - * @todo Switch to using a FormRequest for validation here. - * @author [A. Gianotto] [] - * @since [v1.0] - * @param Request $request - * @param int $licenseId - * @param int $seatId - * @return \Illuminate\Http\RedirectResponse - */ - public function postCheckout(Request $request, $licenseId, $seatId = null) - { - - // Check that the license is valid - if ($license = License::where('id', $licenseId)->first()) { - - // If the license is valid, check that there is an available seat - if ($license->getAvailSeatsCountAttribute() < 1) { - return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); - } - if (!$seatId) { - // Get the next available seat for this license - $next = $license->freeSeat(); - if (!$next) { - return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); - } - if (!$licenseSeat = LicenseSeat::where('id', '=', $next->id)->first()) { - return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); - } - } else { - $licenseSeat = LicenseSeat::where('id', '=', $seatId)->first(); - if (!$licenseSeat) { - return redirect()->route('licenses.index')->with('error', 'License seat is not available for checkout'); - } - } - - - - - - - $this->authorize('checkout', $license); - - // Declare the rules for the form validation - $rules = [ - 'note' => 'string|nullable', - 'asset_id' => 'required_without:assigned_to', - ]; - - // Create a new validator instance from our validation rules - $validator = Validator::make(Input::all(), $rules); - - // If validation fails, we'll exit the operation now. - if ($validator->fails()) { - // Ooops.. something went wrong - return redirect()->back()->withInput()->withErrors($validator); - } - $target = null; - - - // This item is checked out to a an asset - if (request('checkout_to_type')=='asset') { - if (is_null($target = Asset::find(request('asset_id')))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist')); - } - $licenseSeat->asset_id = $request->input('asset_id'); - - // Override asset's assigned user if available - if ($target->checkedOutToUser()) { - $licenseSeat->assigned_to = $target->assigned_to; - } - - } else { - - // Fetch the target and set the license user - if (is_null($target = User::find(request('assigned_to')))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist')); - } - $licenseSeat->assigned_to = request('assigned_to'); - } - - $licenseSeat->user_id = Auth::user()->id; - - - if ($licenseSeat->save()) { - $licenseSeat->logCheckout($request->input('note'), $target); - return redirect()->route("licenses.index")->with('success', trans('admin/licenses/message.checkout.success')); - } - - } - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - - - - - return redirect()->route("licenses.index")->with('error', trans('admin/licenses/message.checkout.error')); - } - - - /** - * Makes the form view to check a license seat back into inventory. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $seatId - * @param string $backTo - * @return \Illuminate\Contracts\View\View - */ - public function getCheckin($seatId = null, $backTo = null) - { - // Check if the asset exists - if (is_null($licenseSeat = LicenseSeat::find($seatId))) { - // Redirect to the asset management page with error - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } - - if (is_null($license = License::find($licenseSeat->license_id))) { - // Redirect to the asset management page with error - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } - - - $this->authorize('checkout', $license); - return view('licenses/checkin', compact('licenseSeat'))->with('backto', $backTo); - } - - - /** - * Validates and stores the license checkin action. - * - * @author [A. Gianotto] [] - * @see LicensesController::getCheckin() method that provides the form view - * @since [v1.0] - * @param int $seatId - * @param string $backTo - * @return \Illuminate\Http\RedirectResponse - */ - public function postCheckin($seatId = null, $backTo = null) - { - // Check if the asset exists - if (is_null($licenseSeat = LicenseSeat::find($seatId))) { - // Redirect to the asset management page with error - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } - - $license = License::find($licenseSeat->license_id); - $this->authorize('checkout', $license); - - if (!$license->reassignable) { - // Not allowed to checkin - Session::flash('error', 'License not reassignable.'); - return redirect()->back()->withInput(); - } - - - $return_to = User::find($licenseSeat->assigned_to); - if (!$return_to) { - $return_to = Asset::find($licenseSeat->asset_id); - } - - // Update the asset data - $licenseSeat->assigned_to = null; - $licenseSeat->asset_id = null; - - // Was the asset updated? - if ($licenseSeat->save()) { - $licenseSeat->logCheckin($license, e(request('note'))); - if ($backTo=='user') { - return redirect()->route("users.show", $return_to->id)->with('success', trans('admin/licenses/message.checkin.success')); - } - return redirect()->route("licenses.show", $licenseSeat->license_id)->with('success', trans('admin/licenses/message.checkin.success')); - } - - // Redirect to the license page with error - return redirect()->route("licenses.index")->with('error', trans('admin/licenses/message.checkin.error')); - } - - /** - * Makes the license detail page. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @return \Illuminate\Contracts\View\View - */ - public function show($licenseId = null) - { - - $license = License::with('assignedusers', 'licenseSeats.user', 'licenseSeats.asset')->find($licenseId); - - if ($license) { - $this->authorize('view', $license); - return view('licenses/view', compact('license')); - } - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - - public function getClone($licenseId = null) - { - if (is_null($license_to_clone = License::find($licenseId))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - $this->authorize('create', License::class); - - $maintained_list = [ - '' => 'Maintained', - '1' => 'Yes', - '0' => 'No' - ]; - //clone the orig - $license = clone $license_to_clone; - $license->id = null; - $license->serial = null; - - // Show the page - return view('licenses/edit') - ->with('depreciation_list', Helper::depreciationList()) - ->with('item', $license) - ->with('maintained_list', $maintained_list); - } - - - /** - * Validates and stores files associated with a license. - * - * @todo Switch to using the AssetFileRequest form request validator. - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @return \Illuminate\Http\RedirectResponse - */ - public function postUpload(AssetFileRequest $request, $licenseId = null) - { - $license = License::find($licenseId); - // the license is valid - $destinationPath = config('app.private_uploads').'/licenses'; - - if (isset($license->id)) { - $this->authorize('update', $license); - - if (Input::hasFile('file')) { - - foreach (Input::file('file') as $file) { - $extension = $file->getClientOriginalExtension(); - $filename = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - $upload_success = $file->move($destinationPath, $filename); - - //Log the upload to the log - $license->logUpload($filename, e($request->input('notes'))); - } - // This being called from a modal seems to confuse redirect()->back() - // It thinks we should go to the dashboard. As this is only used - // from the modal at present, hardcode the redirect. Longterm - // maybe we evaluate something else. - if ($upload_success) { - return redirect()->route('licenses.show', $license->id)->with('success', trans('admin/licenses/message.upload.success')); - } - return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.error')); - } - return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.nofiles')); - } - - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - - /** - * Deletes the selected license file. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @param int $fileId - * @return \Illuminate\Http\RedirectResponse - */ - public function getDeleteFile($licenseId = null, $fileId = null) - { - $license = License::find($licenseId); - $destinationPath = config('app.private_uploads').'/licenses'; - - // the license is valid - if ($license) { - $this->authorize('edit', $license); - $log = Actionlog::find($fileId); - if ($log) { - $full_filename = $destinationPath.'/'.$log->filename; - if (file_exists($full_filename)) { - unlink($destinationPath.'/'.$log->filename); - } - $log->delete(); - return redirect()->back()->with('success', trans('admin/licenses/message.deletefile.success')); - } - - return redirect()->back()->with('error', 'Could not locate that file.'); - - } - - // Redirect to the licence management page - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - - - /** - * Allows the selected file to be viewed. - * - * @author [A. Gianotto] [] - * @since [v1.4] - * @param int $licenseId - * @param int $fileId - * @return \Symfony\Component\HttpFoundation\BinaryFileResponse - */ - public function displayFile($licenseId = null, $fileId = null, $download = true) - { - - $license = License::find($licenseId); - - // the license is valid - if (isset($license->id)) { - $this->authorize('view', $license); - $log = Actionlog::find($fileId); - - if ($log) { - - $file = $log->get_src('licenses'); - if ($file =='') { - return response('File not found on server', 404) - ->header('Content-Type', 'text/plain'); - } - - $mimetype = \File::mimeType($file); - - if (!file_exists($file)) { - return response('File '.$file.' not found on server', 404) - ->header('Content-Type', 'text/plain'); - } - - if ($download != 'true') { - if ($contents = file_get_contents($file)) { - return Response::make($contents)->header('Content-Type', $mimetype); - } - return JsonResponse::create(["error" => "Failed validation: "], 500); - } - return Response::download($file); - } - - } - - - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); - } - - - - /** - * Generates the next free seat ID for checkout. - * - * @todo This is a dumb way to solve this problem. - * Author should refactor. And go hide in a hole and - * think about what she's done. And perhaps find a new - * line of work. And get in the sea. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $licenseId - * @return \Illuminate\Http\RedirectResponse - */ - public function getFreeLicense($licenseId) - { - $this->authorize('checkout', License::class); - if (is_null($license = License::find($licenseId))) { - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } - $seatId = $license->freeSeat($licenseId); - return redirect()->route('licenses.checkout', $seatId); - } -} diff --git a/app/Http/Controllers/LocationsController.php b/app/Http/Controllers/LocationsController.php index c5c5e8d3a0..b78ba7513f 100755 --- a/app/Http/Controllers/LocationsController.php +++ b/app/Http/Controllers/LocationsController.php @@ -1,23 +1,11 @@ ] - * @see LocationsController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that invokes the ajax tables which actually contains + * the content for the locations listing, which is generated in getDatatable. + * + * @author [A. Gianotto] [] + * @see LocationsController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index() { @@ -47,12 +36,13 @@ class LocationsController extends Controller /** - * Returns a form view used to create a new location. - * - * @author [A. Gianotto] [] - * @see LocationsController::postCreate() method that validates and stores the data - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a form view used to create a new location. + * + * @author [A. Gianotto] [] + * @see LocationsController::postCreate() method that validates and stores the data + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create() { @@ -63,18 +53,21 @@ class LocationsController extends Controller /** - * Validates and stores a new location. - * - * @todo Check if a Form Request would work better here. - * @author [A. Gianotto] [] - * @see LocationsController::getCreate() method that makes the form - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse + * Validates and stores a new location. + * + * @todo Check if a Form Request would work better here. + * @author [A. Gianotto] [] + * @see LocationsController::getCreate() method that makes the form + * @since [v1.0] + * @param ImageUploadRequest $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(ImageUploadRequest $request) { $this->authorize('create', Location::class); $location = new Location(); + $location->id = null; // This is required to make Laravels different validation work, it errors if the parameter doesn't exist (maybe a bug)? $location->name = $request->input('name'); $location->parent_id = $request->input('parent_id', null); $location->currency = $request->input('currency', '$'); @@ -88,7 +81,7 @@ class LocationsController extends Controller $location->manager_id = $request->input('manager_id'); $location->user_id = Auth::id(); - $location = $request->handleImages($location,600, public_path().'/uploads/locations'); + $location = $request->handleImages($location); if ($location->save()) { return redirect()->route("locations.index")->with('success', trans('admin/locations/message.create.success')); @@ -98,13 +91,14 @@ class LocationsController extends Controller /** - * Makes a form view to edit location information. - * - * @author [A. Gianotto] [] - * @see LocationsController::postCreate() method that validates and stores - * @param int $locationId - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Makes a form view to edit location information. + * + * @author [A. Gianotto] [] + * @see LocationsController::postCreate() method that validates and stores + * @param int $locationId + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit($locationId = null) { @@ -120,13 +114,15 @@ class LocationsController extends Controller /** - * Validates and stores updated location data from edit form. - * - * @author [A. Gianotto] [] - * @see LocationsController::getEdit() method that makes the form view - * @param int $locationId - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse + * Validates and stores updated location data from edit form. + * + * @author [A. Gianotto] [] + * @see LocationsController::getEdit() method that makes the form view + * @param ImageUploadRequest $request + * @param int $locationId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v1.0] */ public function update(ImageUploadRequest $request, $locationId = null) { @@ -136,10 +132,6 @@ class LocationsController extends Controller return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); } - if ($request->input('parent_id') == $locationId) { - return redirect()->back()->withInput()->with('error', 'A location cannot be its own parent. Please select a different parent location.'); - } - // Update the location data $location->name = $request->input('name'); @@ -153,7 +145,8 @@ class LocationsController extends Controller $location->zip = $request->input('zip'); $location->ldap_ou = $request->input('ldap_ou'); $location->manager_id = $request->input('manager_id'); - $location = $request->handleImages($location,600, public_path().'/uploads/locations'); + + $location = $request->handleImages($location); if ($location->save()) { @@ -163,12 +156,13 @@ class LocationsController extends Controller } /** - * Validates and deletes selected location. - * - * @author [A. Gianotto] [] - * @param int $locationId - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse + * Validates and deletes selected location. + * + * @author [A. Gianotto] [] + * @param int $locationId + * @since [v1.0] + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($locationId) { @@ -177,22 +171,25 @@ class LocationsController extends Controller return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.not_found')); } - if ($location->users->count() > 0) { + if ($location->users()->count() > 0) { return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users')); - - } elseif ($location->children->count() > 0) { + } elseif ($location->children()->count() > 0) { return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_child_loc')); - - } elseif ($location->assets->count() > 0) { + } elseif ($location->assets()->count() > 0) { return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets')); - - } elseif ($location->assignedassets->count() > 0) { + } elseif ($location->assignedassets()->count() > 0) { return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets')); - - } else { - $location->delete(); - return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success')); } + + if ($location->image) { + try { + Storage::disk('public')->delete('locations/'.$location->image); + } catch (\Exception $e) { + \Log::error($e); + } + } + $location->delete(); + return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success')); } @@ -201,13 +198,13 @@ class LocationsController extends Controller * the content for the locations detail page. * * @author [A. Gianotto] [] - * @param int $locationId + * @param int $id * @since [v1.0] * @return \Illuminate\Contracts\View\View */ - public function show($locationId = null) + public function show($id = null) { - $location = Location::find($locationId); + $location = Location::find($id); if (isset($location->id)) { return view('locations/view', compact('location')); diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index 09752adb69..39944b13f6 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -1,20 +1,12 @@ ] - * @see Api\ManufacturersController::index() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that invokes the ajax tables which actually contains + * the content for the manufacturers listing, which is generated in getDatatable. + * + * @author [A. Gianotto] [] + * @see Api\ManufacturersController::index() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index() { @@ -41,12 +34,13 @@ class ManufacturersController extends Controller /** - * Returns a view that displays a form to create a new manufacturer. - * - * @author [A. Gianotto] [] - * @see ManufacturersController::store() - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that displays a form to create a new manufacturer. + * + * @author [A. Gianotto] [] + * @see ManufacturersController::store() + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create() { @@ -61,18 +55,19 @@ class ManufacturersController extends Controller * @author [A. Gianotto] [] * @see ManufacturersController::create() * @since [v1.0] - * @param Request $request + * @param ImageUploadRequest $request * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(ImageUploadRequest $request) { $this->authorize('create', Manufacturer::class); $manufacturer = new Manufacturer; - $manufacturer->name = $request->input('name'); - $manufacturer->user_id = Auth::user()->id; - $manufacturer->url = $request->input('url'); - $manufacturer->support_url = $request->input('support_url'); + $manufacturer->name = $request->input('name'); + $manufacturer->user_id = Auth::id(); + $manufacturer->url = $request->input('url'); + $manufacturer->support_url = $request->input('support_url'); $manufacturer->support_phone = $request->input('support_phone'); $manufacturer->support_email = $request->input('support_email'); $manufacturer = $request->handleImages($manufacturer,600, public_path().'/uploads/manufacturers'); @@ -86,24 +81,25 @@ class ManufacturersController extends Controller } /** - * Returns a view that displays a form to edit a manufacturer. - * - * @author [A. Gianotto] [] - * @see ManufacturersController::update() - * @param int $manufacturerId - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that displays a form to edit a manufacturer. + * + * @author [A. Gianotto] [] + * @see ManufacturersController::update() + * @param int $manufacturerId + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function edit($id = null) + public function edit($manufacturerId = null) { // Handles manufacturer checks and permissions. $this->authorize('update', Manufacturer::class); // Check if the manufacturer exists - if (!$item = Manufacturer::find($id)) { + if (!$item = Manufacturer::find($manufacturerId)) { return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist')); } - + // Show the page return view('manufacturers/edit', compact('item')); } @@ -118,6 +114,7 @@ class ManufacturersController extends Controller * @param int $manufacturerId * @return \Illuminate\Http\RedirectResponse * @since [v1.0] + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(ImageUploadRequest $request, $manufacturerId = null) { @@ -129,12 +126,12 @@ class ManufacturersController extends Controller } // Save the data - $manufacturer->name = $request->input('name'); - $manufacturer->url = $request->input('url'); - $manufacturer->support_url = $request->input('support_url'); + $manufacturer->name = $request->input('name'); + $manufacturer->url = $request->input('url'); + $manufacturer->support_url = $request->input('support_url'); $manufacturer->support_phone = $request->input('support_phone'); $manufacturer->support_email = $request->input('support_email'); - + // Set the model's image property to null if the image is being deleted if ($request->input('image_delete') == 1) { $manufacturer->image = null; @@ -143,7 +140,6 @@ class ManufacturersController extends Controller $manufacturer = $request->handleImages($manufacturer,600, public_path().'/uploads/manufacturers'); - if ($manufacturer->save()) { return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.update.success')); } @@ -151,36 +147,33 @@ class ManufacturersController extends Controller } /** - * Deletes a manufacturer. - * - * @author [A. Gianotto] [] - * @param int $manufacturerId - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse + * Deletes a manufacturer. + * + * @author [A. Gianotto] [] + * @param int $manufacturerId + * @since [v1.0] + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($manufacturerId) { $this->authorize('delete', Manufacturer::class); - // Check if the manufacturer exists - if (is_null($manufacturer = Manufacturer::find($manufacturerId))) { - // Redirect to the manufacturers page + if (is_null($manufacturer = Manufacturer::withCount('models as models_count')->find($manufacturerId))) { return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.not_found')); } - if ($manufacturer->has_models() > 0) { - // Redirect to the asset management page + if (!$manufacturer->isDeletable()) { return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.assoc_users')); } if ($manufacturer->image) { try { - unlink(public_path().'/uploads/manufacturers/'.$manufacturer->image); + Storage::disk('public')->delete('manufacturers/'.$manufacturer->image); } catch (\Exception $e) { \Log::info($e); } } - // Delete the manufacturer $manufacturer->delete(); // Redirect to the manufacturers management page @@ -188,14 +181,15 @@ class ManufacturersController extends Controller } /** - * Returns a view that invokes the ajax tables which actually contains - * the content for the manufacturers detail listing, which is generated via API. - * This data contains a listing of all assets that belong to that manufacturer. - * - * @author [A. Gianotto] [] - * @param int $manufacturerId - * @since [v1.0] - * @return \Illuminate\Contracts\View\View + * Returns a view that invokes the ajax tables which actually contains + * the content for the manufacturers detail listing, which is generated via API. + * This data contains a listing of all assets that belong to that manufacturer. + * + * @author [A. Gianotto] [] + * @param int $manufacturerId + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function show($manufacturerId = null) { @@ -218,6 +212,7 @@ class ManufacturersController extends Controller * @since [v4.1.15] * @param int $manufacturers_id * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function restore($manufacturers_id) { @@ -236,8 +231,4 @@ class ManufacturersController extends Controller return redirect()->back()->with('error', trans('admin/manufacturers/message.does_not_exist')); } - - - - } diff --git a/app/Http/Controllers/ModalController.php b/app/Http/Controllers/ModalController.php index c55ad04a4d..61a3cf10b6 100644 --- a/app/Http/Controllers/ModalController.php +++ b/app/Http/Controllers/ModalController.php @@ -2,38 +2,19 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; - use App\Helpers\Helper; class ModalController extends Controller { - function location() { - return view('modals.location'); - } + function show($type, $itemId = null) { + $view = view("modals.${type}"); - function model() { - return view('modals.model'); + if($type == "statuslabel") { + $view->with('statuslabel_types', Helper::statusTypeList()); + } + if(in_array($type, ['kit-model', 'kit-license', 'kit-consumable', 'kit-accessory'])) { + $view->with('kitId', $itemId); + } + return $view; } - - function statuslabel() { - return view('modals.statuslabel')->with('statuslabel_types', Helper::statusTypeList()); - } - - function supplier() { - return view('modals.supplier'); - } - - function user() { - return view('modals.user'); - } - - function category() { - return view('modals.category'); - } - - function manufacturer() { - return view('modals.manufacturer'); - } - } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index a255aa34b6..787037cfb1 100755 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -1,17 +1,16 @@ location_id = $request->input('location_id'); } - - if (Input::file('avatar')) { - $image = Input::file('avatar'); - $file_name = str_slug($user->first_name."-".$user->last_name).".".$image->getClientOriginalExtension(); - $path = public_path('uploads/avatars/'.$file_name); - Image::make($image->getRealPath())->resize(84, 84)->save($path); + + + if ($request->input('avatar_delete') == 1) { + $user->avatar = null; + } + + + if ($request->hasFile('avatar')) { + $path = 'avatars'; + + if(!Storage::disk('public')->exists($path)) Storage::disk('public')->makeDirectory($path, 775); + + $upload = $image = $request->file('avatar'); + $ext = $image->getClientOriginalExtension(); + $file_name = 'avatar-'.str_random(18).'.'.$ext; + + if ($image->getClientOriginalExtension()!='svg') { + $upload = Image::make($image->getRealPath())->resize(84, 84); + } + + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode()); + + // Remove Current image if exists + if (($user->avatar) && (Storage::disk('public')->exists($path.'/'.$user->avatar))) { + Storage::disk('public')->delete($path.'/'.$user->avatar); + } + $user->avatar = $file_name; } - if (Input::get('avatar_delete') == 1 && Input::file('avatar') == "") { - $user->avatar = null; - } + if ($user->save()) { return redirect()->route('profile')->with('success', 'Account successfully updated'); diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index a892f0c931..fdb7e064cf 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -6,17 +6,18 @@ use App\Models\Accessory; use App\Models\Actionlog; use App\Models\Asset; use App\Models\AssetMaintenance; +use App\Models\CheckoutAcceptance; use App\Models\CustomField; use App\Models\Depreciation; use App\Models\License; use App\Models\Setting; use Carbon\Carbon; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Response; use Illuminate\Support\Facades\View; use Input; use League\Csv\Reader; use Symfony\Component\HttpFoundation\StreamedResponse; -use Illuminate\Http\Request; /** * This controller handles all actions related to Reports for @@ -31,8 +32,6 @@ class ReportsController extends Controller */ public function __construct() { parent::__construct(); - - $this->authorize('reports.view'); } /** @@ -44,6 +43,7 @@ class ReportsController extends Controller */ public function getAccessoryReport() { + $this->authorize('reports.view'); $accessories = Accessory::orderBy('created_at', 'DESC')->with('company')->get(); return view('reports/accessories', compact('accessories')); } @@ -59,6 +59,7 @@ class ReportsController extends Controller */ public function exportAccessoryReport() { + $this->authorize('reports.view'); $accessories = Accessory::orderBy('created_at', 'DESC')->get(); $rows = array(); @@ -99,7 +100,7 @@ class ReportsController extends Controller */ public function getDeprecationReport() { - + $this->authorize('reports.view'); $depreciations = Depreciation::get(); // Grab all the assets $assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'company', 'model.category', 'model.depreciation') @@ -118,7 +119,7 @@ class ReportsController extends Controller */ public function exportDeprecationReport() { - + $this->authorize('reports.view'); // Grab all the assets $assets = Asset::with('model', 'assignedTo', 'assetstatus', 'defaultLoc', 'assetlog') ->orderBy('created_at', 'DESC')->get(); @@ -172,7 +173,7 @@ class ReportsController extends Controller if ($asset->location) { $currency = e($asset->location->currency); } else { - $currency = e(Setting::first()->default_currency); + $currency = e(Setting::getSettings()->default_currency); } $row[] = $asset->purchase_date; @@ -197,6 +198,7 @@ class ReportsController extends Controller */ public function audit() { + $this->authorize('reports.view'); return view('reports/audit'); } @@ -210,7 +212,7 @@ class ReportsController extends Controller */ public function getActivityReport() { - + $this->authorize('reports.view'); return view('reports/activity'); } @@ -224,7 +226,7 @@ class ReportsController extends Controller */ public function getLicenseReport() { - + $this->authorize('reports.view'); $licenses = License::with('depreciation')->orderBy('created_at', 'DESC') ->with('company') ->get(); @@ -242,6 +244,7 @@ class ReportsController extends Controller */ public function exportLicenseReport() { + $this->authorize('reports.view'); $licenses = License::orderBy('created_at', 'DESC')->get(); $rows = [ ]; @@ -292,6 +295,7 @@ class ReportsController extends Controller */ public function getCustomReport() { + $this->authorize('reports.view'); $customfields = CustomField::get(); return view('reports/custom')->with('customfields', $customfields); } @@ -306,8 +310,8 @@ class ReportsController extends Controller */ public function postCustom(Request $request) { - ini_set('max_execution_time', 12000); + $this->authorize('reports.view'); \Debugbar::disable(); @@ -433,6 +437,7 @@ class ReportsController extends Controller if ($request->filled('depreciation')) { $header[] = 'Value'; $header[] = 'Diff'; + $header[] = 'Fully Depreciated'; } if ($request->filled('checkout_date')) { @@ -465,7 +470,7 @@ class ReportsController extends Controller foreach ($customfields as $customfield) { - if (e(Input::get($customfield->db_column_name())) == '1') { + if (e($request->input($customfield->db_column_name())) == '1') { $header[] = $customfield->name; } } @@ -506,6 +511,11 @@ class ReportsController extends Controller $assets->InCategory($request->input('by_category_id')); } + if ($request->filled('by_dept_id')) { + \Log::debug('Only users in dept '.$request->input('by_dept_id')); + $assets->CheckedOutToTargetInDepartment($request->input('by_dept_id')); + } + if ($request->filled('by_manufacturer_id')) { $assets->ByManufacturer($request->input('by_manufacturer_id')); } @@ -672,6 +682,7 @@ class ReportsController extends Controller $diff = ($asset->purchase_cost - $depreciation); $row[] = Helper::formatCurrencyOutput($depreciation); $row[] = Helper::formatCurrencyOutput($diff); + $row[] = ($asset->depreciated_date()!='') ? $asset->depreciated_date()->format('Y-m-d') : ''; } if ($request->filled('checkout_date')) { @@ -742,6 +753,7 @@ class ReportsController extends Controller */ public function getAssetMaintenancesReport() { + $this->authorize('reports.view'); // Grab all the improvements $assetMaintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company') ->orderBy('created_at', 'DESC') @@ -760,6 +772,7 @@ class ReportsController extends Controller */ public function exportAssetMaintenancesReport() { + $this->authorize('reports.view'); // Grab all the improvements $assetMaintenances = AssetMaintenance::with('asset', 'supplier') ->orderBy('created_at', 'DESC') @@ -820,7 +833,21 @@ class ReportsController extends Controller */ public function getAssetAcceptanceReport() { - $assetsForReport = Asset::notYetAccepted()->with('company')->get(); + $this->authorize('reports.view'); + + /** + * Get all assets with pending checkout acceptances + */ + + $acceptances = CheckoutAcceptance::pending()->get(); + + $assetsForReport = $acceptances + ->filter(function($acceptance) { + return $acceptance->checkoutable_type == 'App\Models\Asset'; + }) + ->map(function($acceptance) { + return $acceptance->checkoutable; + }); return view('reports/unaccepted_assets', compact('assetsForReport')); } @@ -834,7 +861,7 @@ class ReportsController extends Controller */ public function exportAssetAcceptanceReport() { - + $this->authorize('reports.view'); // Grab all the improvements $assetsForReport = Actionlog::whereIn('id', $this->getAssetsNotAcceptedYet()) ->get(); @@ -883,6 +910,7 @@ class ReportsController extends Controller */ protected function getCheckedOutAssetsRequiringAcceptance($modelsInCategoriesThatRequireAcceptance) { + $this->authorize('reports.view'); $assets = Asset::deployed() ->inModelList($modelsInCategoriesThatRequireAcceptance) ->select('id') @@ -902,7 +930,7 @@ class ReportsController extends Controller */ protected function getModelsInCategoriesThatRequireAcceptance($assetCategoriesRequiringAcceptance) { - + $this->authorize('reports.view'); return array_pluck(Model::inCategory($assetCategoriesRequiringAcceptance) ->select('id') ->get() @@ -918,7 +946,7 @@ class ReportsController extends Controller */ protected function getCategoriesThatRequireAcceptance() { - + $this->authorize('reports.view'); return array_pluck(Category::requiresAcceptance() ->select('id') ->get() @@ -934,7 +962,7 @@ class ReportsController extends Controller */ protected function getAssetsCheckedOutRequiringAcceptance() { - + $this->authorize('reports.view'); return $this->getCheckedOutAssetsRequiringAcceptance( $this->getModelsInCategoriesThatRequireAcceptance($this->getCategoriesThatRequireAcceptance()) ); @@ -949,6 +977,7 @@ class ReportsController extends Controller */ protected function getAssetsNotAcceptedYet() { + $this->authorize('reports.view'); return Asset::unaccepted(); } } diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 4aa574a6d7..402d29eb28 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1,29 +1,26 @@ ] - * @since [v3.0] - * @return View - */ + * Checks to see whether or not the database has a migrations table + * and a user, otherwise display the setup view. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return View + */ public function getSetupIndex() { + $start_settings['php_version_min'] = false; + if (version_compare(PHP_VERSION, config('app.min_php'), '<')) { + return response('

This software requires PHP version ' . config('app.min_php') . ' or greater. This server is running ' . PHP_VERSION . '.

Please upgrade PHP on this server and try again.

', 500); + } try { - $conn = DB::select('select 2 + 2'); - $start_settings['db_conn'] = true; - $start_settings['db_name'] = DB::connection()->getDatabaseName(); + $conn = DB::select('select 2 + 2'); + $start_settings['db_conn'] = true; + $start_settings['db_name'] = DB::connection()->getDatabaseName(); $start_settings['db_error'] = null; } catch (\PDOException $e) { - $start_settings['db_conn'] = false; - $start_settings['db_name'] = config('database.connections.mysql.database'); + $start_settings['db_conn'] = false; + $start_settings['db_name'] = config('database.connections.mysql.database'); $start_settings['db_error'] = $e->getMessage(); } - $protocol = array_key_exists('HTTPS', $_SERVER) && ( $_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; + $protocol = array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS']) ? 'https://' : 'http://'; $host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null; $port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null; - if (($protocol === 'http://' && $port != '80') || ($protocol === 'https://' && $port != '443')) { + if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) { $host .= ':' . $port; } $pageURL = $protocol . $host . $_SERVER['REQUEST_URI']; - $start_settings['url_valid'] = (url('/').'/setup' === $pageURL); + $start_settings['url_valid'] = (url('/') . '/setup' === $pageURL); - $start_settings['url_config'] = url('/'); - $start_settings['real_url'] = $pageURL; + $start_settings['url_config'] = url('/'); + $start_settings['real_url'] = $pageURL; + $start_settings['php_version_min'] = true; // Curl the .env file to make sure it's not accessible via a browser - $ch = curl_init($protocol . $host.'/.env'); + $ch = curl_init($protocol . $host . '/.env'); curl_setopt($ch, CURLOPT_HEADER, true); // we want headers curl_setopt($ch, CURLOPT_NOBODY, true); // we don't need body curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); - $output = curl_exec($ch); + $output = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - if ($httpcode == 404 || $httpcode == 403) { + if (404 == $httpcode || 403 == $httpcode || 0 == $httpcode) { $start_settings['env_exposed'] = false; } else { $start_settings['env_exposed'] = true; } - - if (\App::Environment('production') && (config('app.debug')==true)) { + if (\App::Environment('production') && (true == config('app.debug'))) { $start_settings['debug_exposed'] = true; } else { $start_settings['debug_exposed'] = false; } $environment = app()->environment(); - if ($environment!='production') { - $start_settings['env'] = $environment; + if ('production' != $environment) { + $start_settings['env'] = $environment; $start_settings['prod'] = false; } else { - $start_settings['env'] = $environment; + $start_settings['env'] = $environment; $start_settings['prod'] = true; - } if (function_exists('posix_getpwuid')) { // Probably Linux - $owner = posix_getpwuid(fileowner($_SERVER["SCRIPT_FILENAME"])); + $owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME'])); $start_settings['owner'] = $owner['name']; } else { // Windows // TODO: Is there a way of knowing if a windows user has elevated permissions @@ -114,214 +115,208 @@ class SettingsController extends Controller $start_settings['owner'] = ''; } - if (($start_settings['owner']==='root') || ($start_settings['owner']==='0')) { + if (('root' === $start_settings['owner']) || ('0' === $start_settings['owner'])) { $start_settings['owner_is_admin'] = true; } else { $start_settings['owner_is_admin'] = false; } if ((is_writable(storage_path())) - && (is_writable(storage_path().'/framework')) - && (is_writable(storage_path().'/framework/cache')) - && (is_writable(storage_path().'/framework/sessions')) - && (is_writable(storage_path().'/framework/views')) - && (is_writable(storage_path().'/logs')) + && (is_writable(storage_path() . '/framework')) + && (is_writable(storage_path() . '/framework/cache')) + && (is_writable(storage_path() . '/framework/sessions')) + && (is_writable(storage_path() . '/framework/views')) + && (is_writable(storage_path() . '/logs')) ) { $start_settings['writable'] = true; } else { $start_settings['writable'] = false; } - $start_settings['gd'] = extension_loaded('gd'); + return view('setup/index') - ->with('step', 1) - ->with('start_settings', $start_settings) - ->with('section', 'Pre-Flight Check'); + ->with('step', 1) + ->with('start_settings', $start_settings) + ->with('section', 'Pre-Flight Check'); } - /** - * Save the first admin user from Setup. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return Redirect - */ + * Save the first admin user from Setup. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return Redirect + */ public function postSaveFirstAdmin(SetupUserRequest $request) { - - - $user = new User; - $user->first_name = $data['first_name']= $request->input('first_name'); - $user->last_name = $request->input('last_name'); - $user->email = $data['email'] = $request->input('email'); - $user->activated = 1; - $permissions = array('superuser' => 1); + $user = new User(); + $user->first_name = $data['first_name'] = $request->input('first_name'); + $user->last_name = $request->input('last_name'); + $user->email = $data['email'] = $request->input('email'); + $user->activated = 1; + $permissions = ['superuser' => 1]; $user->permissions = json_encode($permissions); - $user->username = $data['username'] = $request->input('username'); - $user->password = bcrypt($request->input('password')); - $data['password'] = $request->input('password'); + $user->username = $data['username'] = $request->input('username'); + $user->password = bcrypt($request->input('password')); + $data['password'] = $request->input('password'); - $settings = new Setting; + $settings = new Setting(); $settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0); - $settings->site_name = $request->input('site_name'); - $settings->alert_email = $request->input('email'); - $settings->alerts_enabled = 1; - $settings->pwd_secure_min = 10; - $settings->brand = 1; - $settings->locale = $request->input('locale', 'en'); - $settings->default_currency = $request->input('default_currency', "USD"); - $settings->user_id = 1; - $settings->email_domain = $request->input('email_domain'); - $settings->email_format = $request->input('email_format'); - $settings->next_auto_tag_base = 1; - $settings->auto_increment_assets = $request->input('auto_increment_assets', 0); - $settings->auto_increment_prefix = $request->input('auto_increment_prefix'); + $settings->site_name = $request->input('site_name'); + $settings->alert_email = $request->input('email'); + $settings->alerts_enabled = 1; + $settings->pwd_secure_min = 10; + $settings->brand = 1; + $settings->locale = $request->input('locale', 'en'); + $settings->default_currency = $request->input('default_currency', 'USD'); + $settings->user_id = 1; + $settings->email_domain = $request->input('email_domain'); + $settings->email_format = $request->input('email_format'); + $settings->next_auto_tag_base = 1; + $settings->auto_increment_assets = $request->input('auto_increment_assets', 0); + $settings->auto_increment_prefix = $request->input('auto_increment_prefix'); - - if ((!$user->isValid()) || (!$settings->isValid())) { + if ((! $user->isValid()) || (! $settings->isValid())) { return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors()); } else { $user->save(); Auth::login($user, true); $settings->save(); - if (Input::get('email_creds')=='1') { - $data = array(); - $data['email'] = $user->email; - $data['username'] = $user->username; + if ($request->input('email_creds') == '1') { + $data = []; + $data['email'] = $user->email; + $data['username'] = $user->username; $data['first_name'] = $user->first_name; - $data['last_name'] = $user->last_name; - $data['password'] = $request->input('password'); + $data['last_name'] = $user->last_name; + $data['password'] = $request->input('password'); $user->notify(new FirstAdminNotification($data)); - - /*Mail::send(['text' => 'emails.firstadmin'], $data, function ($m) use ($data) { - $m->to($data['email'], $data['first_name']); - $m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name')); - $m->subject(trans('mail.your_credentials')); - });*/ } - - return redirect()->route('setup.done'); } - - } /** - * Return the admin user creation form in Setup. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return View - */ + * Return the admin user creation form in Setup. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return View + */ public function getSetupUser() { return view('setup/user') - ->with('step', 3) - ->with('section', 'Create a User'); + ->with('step', 3) + ->with('section', 'Create a User'); } /** - * Return the view that tells the user that the Setup is done. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return View - */ + * Return the view that tells the user that the Setup is done. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return View + */ public function getSetupDone() { - return view('setup/done') - ->with('step', 4) - ->with('section', 'Done!'); + ->with('step', 4) + ->with('section', 'Done!'); } /** - * Migrate the database tables, and return the output - * to a view for Setup - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return View - */ + * Migrate the database tables, and return the output + * to a view for Setup. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return View + */ public function getSetupMigrate() { - Artisan::call('migrate', ['--force' => true]); + if ((! file_exists(storage_path() . '/oauth-private.key')) || (! file_exists(storage_path() . '/oauth-public.key'))) { - $output = Artisan::output(); - - if ((!file_exists(storage_path().'/oauth-private.key')) || (!file_exists(storage_path().'/oauth-public.key'))) { - Artisan::call('migrate', ['--force' => true]); + Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]); Artisan::call('passport:install'); } - return view('setup/migrate') - ->with('output', $output) - ->with('step', 2) - ->with('section', 'Create Database Tables'); - + ->with('output', 'Databases installed!') + ->with('step', 2) + ->with('section', 'Create Database Tables'); } - /** - * Return a view that shows some of the key settings. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return View - */ + * Return a view that shows some of the key settings. + * + * @author [A. Gianotto] [] + * + * @since [v1.0] + * + * @return View + */ public function index() { - $settings = Setting::all(); + $settings = Setting::getSettings(); + return view('settings/index', compact('settings')); } - /** - * Return the admin settings page - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return View - */ + * Return the admin settings page. + * + * @author [A. Gianotto] [] + * + * @since [v1.0] + * + * @return View + */ public function getEdit() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings/general', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getSettings() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings/general', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postSettings(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } @@ -332,26 +327,27 @@ class SettingsController extends Controller $setting->modellist_displays = implode(',', $request->input('show_in_model_list')); } - $setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0'); - $setting->load_remote = $request->input('load_remote', '0'); - $setting->unique_serial = $request->input('unique_serial', '0'); - $setting->show_images_in_email = $request->input('show_images_in_email', '0'); - $setting->show_archived_in_list = $request->input('show_archived_in_list', '0'); - $setting->dashboard_message = $request->input('dashboard_message'); - $setting->email_domain = $request->input('email_domain'); - $setting->email_format = $request->input('email_format'); - $setting->username_format = $request->input('username_format'); - $setting->require_accept_signature = $request->input('require_accept_signature'); - if (!config('app.lock_passwords')) { + $setting->unique_serial = $request->input('unique_serial', '0'); + $setting->show_images_in_email = $request->input('show_images_in_email', '0'); + $setting->show_archived_in_list = $request->input('show_archived_in_list', '0'); + $setting->dashboard_message = $request->input('dashboard_message'); + $setting->email_domain = $request->input('email_domain'); + $setting->email_format = $request->input('email_format'); + $setting->username_format = $request->input('username_format'); + $setting->require_accept_signature = $request->input('require_accept_signature'); + $setting->show_assigned_assets = $request->input('show_assigned_assets', '0'); + if (! config('app.lock_passwords')) { $setting->login_note = $request->input('login_note'); } - $setting->default_eula_text = $request->input('default_eula_text'); - $setting->thumbnail_max_h = $request->input('thumbnail_max_h'); + $setting->default_eula_text = $request->input('default_eula_text'); + $setting->thumbnail_max_h = $request->input('thumbnail_max_h'); $setting->privacy_policy_link = $request->input('privacy_policy_link'); - if (Input::get('per_page')!='') { + $setting->depreciation_method = $request->input('depreciation_method'); + + if ($request->input('per_page') != '') { $setting->per_page = $request->input('per_page'); } else { $setting->per_page = 200; @@ -361,149 +357,174 @@ class SettingsController extends Controller return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getBranding() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.branding', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postBranding(ImageUploadRequest $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - $setting->brand = $request->input('brand', '1'); - $setting->header_color = $request->input('header_color'); - $setting->support_footer = $request->input('support_footer'); - $setting->version_footer = $request->input('version_footer'); - $setting->footer_text = $request->input('footer_text'); - $setting->skin = $request->input('skin'); + $setting->brand = $request->input('brand', '1'); + $setting->header_color = $request->input('header_color'); + $setting->support_footer = $request->input('support_footer'); + $setting->version_footer = $request->input('version_footer'); + $setting->footer_text = $request->input('footer_text'); + $setting->skin = $request->input('skin'); $setting->show_url_in_emails = $request->input('show_url_in_emails', '0'); - $setting->logo_print_assets = $request->input('logo_print_assets', '0'); - - + $setting->logo_print_assets = $request->input('logo_print_assets', '0'); // Only allow the site name and CSS to be changed if lock_passwords is false // Because public demos make people act like dicks - if (!config('app.lock_passwords')) { - $setting->site_name = $request->input('site_name'); + if (! config('app.lock_passwords')) { + $setting->site_name = $request->input('site_name'); $setting->custom_css = $request->input('custom_css'); } + $setting = $request->handleImages($setting,600,'logo','', 'logo'); - // If the user wants to clear the logo, reset the brand type - if ($request->input('clear_logo')=='1') { - $setting->logo = null; - $setting->brand = 1; - // If they are uploading an image, validate it and upload it - } elseif ($request->hasFile('image')) { - - if (!config('app.lock_passwords')) { - $image = $request->file('image'); - $file_name = "logo.".$image->getClientOriginalExtension(); - $path = public_path('uploads'); - if ($image->getClientOriginalExtension()!='svg') { - - Image::make($image->getRealPath())->resize(null, 150, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path.'/'.$file_name); - } else { - - // This is kinda copypasta from the ImageUploadRequest - should refactor the ImageUploadRequest to better handle maybe - $sanitizer = new Sanitizer(); - $dirtySVG = file_get_contents($image->getRealPath()); - $cleanSVG = $sanitizer->sanitize($dirtySVG); - - try { - file_put_contents($path.'/'.$file_name, $cleanSVG); - } catch (\Exception $e) { - \Log::debug($e); - } - } - $setting->logo = $file_name; - } + if ('1' == $request->input('clear_logo')) { + Storage::disk('public')->delete($setting->logo); + $setting->logo = null; + $setting->brand = 1; } + + $setting = $request->handleImages($setting,600,'email_logo','', 'email_logo'); + + + if ('1' == $request->input('clear_email_logo')) { + Storage::disk('public')->delete($setting->email_logo); + $setting->email_logo = null; + // If they are uploading an image, validate it and upload it + } + + + $setting = $request->handleImages($setting,600,'label_logo','', 'label_logo'); + + + if ('1' == $request->input('clear_label_logo')) { + Storage::disk('public')->delete($setting->label_logo); + $setting->label_logo = null; + + } + + + // If the user wants to clear the favicon... + if ($request->hasFile('favicon')) { + $favicon_image = $favicon_upload = $request->file('favicon'); + $favicon_ext = $favicon_image->getClientOriginalExtension(); + $setting->favicon = $favicon_file_name = 'favicon-uploaded.' . $favicon_ext; + + if (($favicon_image->getClientOriginalExtension()!='ico') && ($favicon_image->getClientOriginalExtension()!='svg')) { + $favicon_upload = Image::make($favicon_image->getRealPath())->resize(null, 36, function ($constraint) { + $constraint->aspectRatio(); + $constraint->upsize(); + }); + + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($favicon_file_name, (string) $favicon_upload->encode()); + } else { + Storage::disk('public')->put($favicon_file_name, file_get_contents($request->file('favicon'))); + } + + + // Remove Current image if exists + if (($setting->favicon) && (file_exists($favicon_file_name))) { + Storage::disk('public')->delete($favicon_file_name); + } + } elseif ('1' == $request->input('clear_favicon')) { + Storage::disk('public')->delete($setting->clear_favicon); + $setting->favicon = null; + + // If they are uploading an image, validate it and upload it + } + if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getSecurity() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.security', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postSecurity(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } + if (! config('app.lock_passwords')) { - - if (!config('app.lock_passwords')) { - - if ($request->input('two_factor_enabled')=='') { + if ('' == $request->input('two_factor_enabled')) { $setting->two_factor_enabled = null; } else { $setting->two_factor_enabled = $request->input('two_factor_enabled'); } - # remote user login - $setting->login_remote_user_enabled = (int)$request->input('login_remote_user_enabled'); - $setting->login_common_disabled = (int)$request->input('login_common_disabled'); + // remote user login + $setting->login_remote_user_enabled = (int) $request->input('login_remote_user_enabled'); + $setting->login_common_disabled = (int) $request->input('login_common_disabled'); $setting->login_remote_user_custom_logout_url = $request->input('login_remote_user_custom_logout_url'); + $setting->login_remote_user_header_name = $request->input('login_remote_user_header_name'); } - $setting->pwd_secure_uncommon = (int) $request->input('pwd_secure_uncommon'); - $setting->pwd_secure_min = (int) $request->input('pwd_secure_min'); + $setting->pwd_secure_uncommon = (int) $request->input('pwd_secure_uncommon'); + $setting->pwd_secure_min = (int) $request->input('pwd_secure_min'); $setting->pwd_secure_complexity = ''; @@ -511,49 +532,49 @@ class SettingsController extends Controller $setting->pwd_secure_complexity = implode('|', $request->input('pwd_secure_complexity')); } - - if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getLocalization() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.localization', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postLocalization(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - if (!config('app.lock_passwords')) { + if (! config('app.lock_passwords')) { $setting->locale = $request->input('locale', 'en'); } - $setting->default_currency = $request->input('default_currency', '$'); + $setting->default_currency = $request->input('default_currency', '$'); $setting->date_display_format = $request->input('date_display_format'); $setting->time_display_format = $request->input('time_display_format'); @@ -561,257 +582,267 @@ class SettingsController extends Controller return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getAlerts() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.alerts', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postAlerts(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - $alert_email = rtrim($request->input('alert_email'), ','); - $alert_email = trim($alert_email); + $alert_email = rtrim($request->input('alert_email'), ','); + $alert_email = trim($alert_email); $admin_cc_email = rtrim($request->input('admin_cc_email'), ','); $admin_cc_email = trim($admin_cc_email); - $setting->alert_email = $alert_email; - $setting->admin_cc_email = $admin_cc_email; - $setting->alerts_enabled = $request->input('alerts_enabled', '0'); - $setting->alert_interval = $request->input('alert_interval'); - $setting->alert_threshold = $request->input('alert_threshold'); - $setting->audit_interval = $request->input('audit_interval'); - $setting->audit_warning_days = $request->input('audit_warning_days'); + $setting->alert_email = $alert_email; + $setting->admin_cc_email = $admin_cc_email; + $setting->alerts_enabled = $request->input('alerts_enabled', '0'); + $setting->alert_interval = $request->input('alert_interval'); + $setting->alert_threshold = $request->input('alert_threshold'); + $setting->audit_interval = $request->input('audit_interval'); + $setting->audit_warning_days = $request->input('audit_warning_days'); $setting->show_alerts_in_menu = $request->input('show_alerts_in_menu', '0'); if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getSlack() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.slack', compact('setting')); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postSlack(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } $validatedData = $request->validate([ - 'slack_endpoint' => 'url|required_with:slack_channel|nullable', 'slack_channel' => 'regex:/(? 'string|nullable', ]); + if ($validatedData) { $setting->slack_endpoint = $request->input('slack_endpoint'); $setting->slack_channel = $request->input('slack_channel'); $setting->slack_botname = $request->input('slack_botname'); - $setting->save(); + } + + if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); - } return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getAssetTags() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.asset_tags', compact('setting')); } - /** - * Saves settings from form + * Saves settings from form. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postAssetTags(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } $setting->auto_increment_prefix = $request->input('auto_increment_prefix'); $setting->auto_increment_assets = $request->input('auto_increment_assets', '0'); - $setting->zerofill_count = $request->input('zerofill_count'); - $setting->next_auto_tag_base = $request->input('next_auto_tag_base'); + $setting->zerofill_count = $request->input('zerofill_count'); + $setting->next_auto_tag_base = $request->input('next_auto_tag_base'); if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function getBarcodes() { - $setting = Setting::first(); + $setting = Setting::getSettings(); $is_gd_installed = extension_loaded('gd'); - return view('settings.barcodes', compact('setting'))->with('is_gd_installed',$is_gd_installed); + return view('settings.barcodes', compact('setting'))->with('is_gd_installed', $is_gd_installed); } - /** - * Saves settings from form + * Saves settings from form. * * @author [A. Gianotto] [] + * * @since [v1.0] + * * @return View */ public function postBarcodes(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - $setting->qr_code = $request->input('qr_code', '0'); - $setting->alt_barcode = $request->input('alt_barcode'); + $setting->qr_code = $request->input('qr_code', '0'); + $setting->alt_barcode = $request->input('alt_barcode'); $setting->alt_barcode_enabled = $request->input('alt_barcode_enabled', '0'); - $setting->barcode_type = $request->input('barcode_type'); - $setting->qr_text = $request->input('qr_text'); - + $setting->barcode_type = $request->input('barcode_type'); + $setting->qr_text = $request->input('qr_text'); if ($setting->save()) { return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function getPhpInfo() { - if (config('app.debug')=== true) { + if (true === config('app.debug')) { return view('settings.phpinfo'); } + return redirect()->route('settings.index') ->with('error', 'PHP syetem debugging information is only available when debug is enabled in your .env file.'); } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function getLabels() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.labels', compact('setting')); } - /** - * Saves settings from form + * Saves settings from form. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function postLabels(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - $setting->labels_per_page = $request->input('labels_per_page'); - $setting->labels_width = $request->input('labels_width'); - $setting->labels_height = $request->input('labels_height'); - $setting->labels_pmargin_left = $request->input('labels_pmargin_left'); - $setting->labels_pmargin_right = $request->input('labels_pmargin_right'); - $setting->labels_pmargin_top = $request->input('labels_pmargin_top'); - $setting->labels_pmargin_bottom = $request->input('labels_pmargin_bottom'); - $setting->labels_display_bgutter = $request->input('labels_display_bgutter'); - $setting->labels_display_sgutter = $request->input('labels_display_sgutter'); - $setting->labels_fontsize = $request->input('labels_fontsize'); - $setting->labels_pagewidth = $request->input('labels_pagewidth'); - $setting->labels_pageheight = $request->input('labels_pageheight'); + $setting->labels_per_page = $request->input('labels_per_page'); + $setting->labels_width = $request->input('labels_width'); + $setting->labels_height = $request->input('labels_height'); + $setting->labels_pmargin_left = $request->input('labels_pmargin_left'); + $setting->labels_pmargin_right = $request->input('labels_pmargin_right'); + $setting->labels_pmargin_top = $request->input('labels_pmargin_top'); + $setting->labels_pmargin_bottom = $request->input('labels_pmargin_bottom'); + $setting->labels_display_bgutter = $request->input('labels_display_bgutter'); + $setting->labels_display_sgutter = $request->input('labels_display_sgutter'); + $setting->labels_fontsize = $request->input('labels_fontsize'); + $setting->labels_pagewidth = $request->input('labels_pagewidth'); + $setting->labels_pageheight = $request->input('labels_pageheight'); + $setting->labels_display_company_name = $request->input('labels_display_company_name', '0'); $setting->labels_display_company_name = $request->input('labels_display_company_name', '0'); @@ -832,13 +863,13 @@ class SettingsController extends Controller $setting->labels_display_tag = 1; } else { $setting->labels_display_tag = 0; - } + } - if ($request->filled('labels_display_tag')) { - $setting->labels_display_tag = 1; - } else { - $setting->labels_display_tag = 0; - } + if ($request->filled('labels_display_tag')) { + $setting->labels_display_tag = 1; + } else { + $setting->labels_display_tag = 0; + } if ($request->filled('labels_display_model')) { $setting->labels_display_model = 1; @@ -850,167 +881,210 @@ class SettingsController extends Controller return redirect()->route('settings.index') ->with('success', trans('admin/settings/message.update.success')); } + return redirect()->back()->withInput()->withErrors($setting->getErrors()); - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function getLdapSettings() { - $setting = Setting::first(); + $setting = Setting::getSettings(); + return view('settings.ldap', compact('setting')); } - /** - * Saves settings from form + * Saves settings from form. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function postLdapSettings(Request $request) { - - if (is_null($setting = Setting::first())) { + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } - $setting->ldap_enabled = $request->input('ldap_enabled', '0'); - $setting->ldap_server = $request->input('ldap_server'); + $setting->ldap_enabled = $request->input('ldap_enabled', '0'); + $setting->ldap_server = $request->input('ldap_server'); $setting->ldap_server_cert_ignore = $request->input('ldap_server_cert_ignore', false); - $setting->ldap_uname = $request->input('ldap_uname'); - if (Input::filled('ldap_pword')) { + $setting->ldap_uname = $request->input('ldap_uname'); + if ($request->input('ldap_pword') !== '') { $setting->ldap_pword = Crypt::encrypt($request->input('ldap_pword')); } - $setting->ldap_basedn = $request->input('ldap_basedn'); - $setting->ldap_filter = $request->input('ldap_filter'); - $setting->ldap_username_field = $request->input('ldap_username_field'); - $setting->ldap_lname_field = $request->input('ldap_lname_field'); - $setting->ldap_fname_field = $request->input('ldap_fname_field'); + $setting->ldap_basedn = $request->input('ldap_basedn'); + $setting->ldap_filter = $request->input('ldap_filter'); + $setting->ldap_username_field = $request->input('ldap_username_field'); + $setting->ldap_lname_field = $request->input('ldap_lname_field'); + $setting->ldap_fname_field = $request->input('ldap_fname_field'); $setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query'); - $setting->ldap_version = $request->input('ldap_version'); - $setting->ldap_active_flag = $request->input('ldap_active_flag'); - $setting->ldap_emp_num = $request->input('ldap_emp_num'); - $setting->ldap_email = $request->input('ldap_email'); - $setting->ad_domain = $request->input('ad_domain'); - $setting->is_ad = $request->input('is_ad', '0'); - $setting->ldap_tls = $request->input('ldap_tls', '0'); - $setting->ldap_pw_sync = $request->input('ldap_pw_sync', '0'); + $setting->ldap_version = $request->input('ldap_version'); + $setting->ldap_active_flag = $request->input('ldap_active_flag'); + $setting->ldap_emp_num = $request->input('ldap_emp_num'); + $setting->ldap_email = $request->input('ldap_email'); + $setting->ad_domain = $request->input('ad_domain'); + $setting->is_ad = $request->input('is_ad', '0'); + $setting->ldap_tls = $request->input('ldap_tls', '0'); + $setting->ldap_pw_sync = $request->input('ldap_pw_sync', '0'); $setting->custom_forgot_pass_url = $request->input('custom_forgot_pass_url'); if ($setting->save()) { - return redirect()->route('settings.index') + return redirect()->route('settings.ldap.index') ->with('success', trans('admin/settings/message.update.success')); } - return redirect()->back()->withInput()->withErrors($setting->getErrors()); + return redirect()->back()->withInput()->withErrors($setting->getErrors()); } + /** + * Return a form to allow a super admin to update settings. + * + * @author Johnson Yi + * + * @since v5.0.0 + * + * @return View + */ + public function getSamlSettings() + { + $setting = Setting::getSettings(); - - - + return view('settings.saml', compact('setting')); + } /** - * Show the listing of backups - * - * @author [A. Gianotto] [] - * @since [v1.8] - * @return View - */ + * Saves settings from form. + * + * @author Johnson Yi + * + * @since v5.0.0 + * + * @return View + */ + public function postSamlSettings(SettingsSamlRequest $request) + { + if (is_null($setting = Setting::getSettings())) { + return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); + } + + $setting->saml_enabled = $request->input('saml_enabled', '0'); + $setting->saml_idp_metadata = $request->input('saml_idp_metadata'); + $setting->saml_attr_mapping_username = $request->input('saml_attr_mapping_username'); + $setting->saml_forcelogin = $request->input('saml_forcelogin', '0'); + $setting->saml_slo = $request->input('saml_slo', '0'); + if (!empty($request->input('saml_sp_privatekey'))) { + $setting->saml_sp_x509cert = $request->input('saml_sp_x509cert'); + $setting->saml_sp_privatekey = $request->input('saml_sp_privatekey'); + } + $setting->saml_custom_settings = $request->input('saml_custom_settings'); + + if ($setting->save()) { + return redirect()->route('settings.saml.index') + ->with('success', trans('admin/settings/message.update.success')); + } + + return redirect()->back()->withInput()->withErrors($setting->getErrors()); + } + + /** + * Show the listing of backups. + * + * @author [A. Gianotto] [] + * + * @since [v1.8] + * + * @return View + */ public function getBackups() { - $path = storage_path().'/app/'.config('backup.backup.name'); + $path = 'app/backups'; + $backup_files = Storage::files($path); + $files = []; - $files = array(); + if (count($backup_files) > 0) { + for ($f = 0; $f < count($backup_files); ++$f) { - if ($handle = opendir($path)) { + // Skip dotfiles like .gitignore and .DS_STORE + if ((substr(basename($backup_files[$f]), 0, 1) != '.')) { + + $files[] = [ + 'filename' => basename($backup_files[$f]), + 'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])), + 'modified' => Storage::lastModified($backup_files[$f]), + ]; - /* This is the correct way to loop over the directory. */ - while (false !== ($entry = readdir($handle))) { - clearstatcache(); - if (substr(strrchr($entry, '.'), 1)=='zip') { - $files[] = array( - 'filename' => $entry, - 'filesize' => Setting::fileSizeConvert(filesize($path.'/'.$entry)), - 'modified' => filemtime($path.'/'.$entry) - ); } - } - closedir($handle); - rsort($files); - } + } + } return view('settings/backups', compact('path', 'files')); } - /** - * Process the backup. - * - * @author [A. Gianotto] [] - * @since [v1.8] - * @return Redirect - */ - + * Process the backup. + * + * @author [A. Gianotto] [] + * + * @since [v1.8] + * + * @return Redirect + */ public function postBackups() { - - if (!config('app.lock_passwords')) { + if (! config('app.lock_passwords')) { Artisan::call('backup:run'); $output = Artisan::output(); // Backup completed - if (!preg_match('/failed/', $output)) { + if (! preg_match('/failed/', $output)) { return redirect()->route('settings.backups.index') ->with('success', trans('admin/settings/message.backup.generated')); } - $formatted_output = str_replace('Backup completed!', '', $output); - $output_split = explode('...', $formatted_output); + $output_split = explode('...', $formatted_output); if (array_key_exists(2, $output_split)) { - return redirect()->route("settings.backups.index")->with('error', $output_split[2]); + return redirect()->route('settings.backups.index')->with('error', $output_split[2]); } - return redirect()->route("settings.backups.index")->with('error', $formatted_output); - - } - return redirect()->route("settings.backups.index")->with('error', trans('general.feature_disabled')); - - + return redirect()->route('settings.backups.index')->with('error', $formatted_output); + } + return redirect()->route('settings.backups.index')->with('error', trans('general.feature_disabled')); } - /** - * Download the backup file - * - * @author [A. Gianotto] [] - * @since [v1.8] - * @return Redirect - */ + * Download the backup file. + * + * @author [A. Gianotto] [] + * + * @since [v1.8] + * + * @return Storage + */ public function downloadFile($filename = null) { - if (!config('app.lock_passwords')) { - $path = storage_path().'/app/'.config('backup.backup.name'); - $file = $path.'/'.$filename; - if (file_exists($file)) { - return Response::download($file); - } else { + $path = 'app/backups'; + if (! config('app.lock_passwords')) { + if (Storage::exists($path . '/' . $filename)) { + return Storage::download($path . '/' . $filename); + } else { // Redirect to the backup page return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found')); } @@ -1018,42 +1092,44 @@ class SettingsController extends Controller // Redirect to the backup page return redirect()->route('settings.backups.index')->with('error', trans('general.feature_disabled')); } - - } /** - * Delete the backup file - * - * @author [A. Gianotto] [] - * @since [v1.8] - * @return View - */ + * Delete the backup file. + * + * @author [A. Gianotto] [] + * + * @since [v1.8] + * + * @return View + */ public function deleteFile($filename = null) { + if (! config('app.lock_passwords')) { + $path = 'app/backups'; - if (!config('app.lock_passwords')) { - - $path = storage_path().'/app/'.config('backup.backup.name'); - $file = $path.'/'.$filename; - if (file_exists($file)) { - unlink($file); - return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted')); + if (Storage::exists($path . '/' . $filename)) { + try { + Storage::delete($path . '/' . $filename); + return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted')); + } catch (\Exception $e) { + \Log::debug($e); + } } else { return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found')); } } else { return redirect()->route('settings.backups.index')->with('error', trans('general.feature_disabled')); } - } - /** * Return a form to allow a super admin to update settings. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ public function getPurge() @@ -1062,26 +1138,28 @@ class SettingsController extends Controller } /** - * Purges soft-deletes - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return View - */ - public function postPurge() + * Purges soft-deletes. + * + * @author [A. Gianotto] [] + * + * @since [v3.0] + * + * @return View + */ + public function postPurge(Request $request) { - if (!config('app.lock_passwords')) { - if (Input::get('confirm_purge')=='DELETE') { + if (! config('app.lock_passwords')) { + if ('DELETE' == $request->input('confirm_purge')) { // Run a backup immediately before processing Artisan::call('backup:run'); - Artisan::call('snipeit:purge', ['--force'=>'true','--no-interaction'=>true]); + Artisan::call('snipeit:purge', ['--force' => 'true', '--no-interaction' => true]); $output = Artisan::output(); + return view('settings/purge') - ->with('output', $output)->with('success', trans('admin/settings/message.purge.success')); + ->with('output', $output)->with('success', trans('admin/settings/message.purge.success')); } else { return redirect()->back()->with('error', trans('admin/settings/message.purge.validation_failed')); } - } else { return redirect()->back()->with('error', trans('general.feature_disabled')); } @@ -1094,34 +1172,41 @@ class SettingsController extends Controller * in the routes file if you want to be able to cache the routes. * * @author [A. Gianotto] [] + * * @since [v4.0] + * * @return View */ - public function api() { + public function api() + { return view('settings.api'); } - - /** - * Test the email configuration + * Test the email configuration. * * @author [A. Gianotto] [] + * * @since [v3.0] + * * @return Redirect */ public function ajaxTestEmail() { try { - Mail::send('emails.test', [], function ($m) { - $m->to(config('mail.from.address'), config('mail.from.name')); - $m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name')); - $m->subject(trans('mail.test_email')); - }); + (new User())->forceFill([ + 'name' => config('mail.from.name'), + 'email' => config('mail.from.address'), + ])->notify(new MailTest()); + return response()->json(Helper::formatStandardApiResponse('success', null, 'Maiol sent!')); } catch (Exception $e) { return response()->json(Helper::formatStandardApiResponse('success', null, $e->getMessage())); } - } -} + + public function getLoginAttempts() + { + return view('settings.logins'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/StatuslabelsController.php b/app/Http/Controllers/StatuslabelsController.php index 7cc48f08fe..e1b7ffe0ef 100755 --- a/app/Http/Controllers/StatuslabelsController.php +++ b/app/Http/Controllers/StatuslabelsController.php @@ -1,21 +1,11 @@ authorize('create', Statuslabel::class); - $item = new Statuslabel; - $use_statuslabel_type = $item->getStatuslabelType(); - $statuslabel_types = Helper::statusTypeList(); - return view('statuslabels/edit', compact('statuslabel_types', 'item'))->with('use_statuslabel_type', $use_statuslabel_type); + return view('statuslabels/edit') + ->with('item', new Statuslabel) + ->with('statuslabel_types', Helper::statusTypeList()); } @@ -70,6 +60,7 @@ class StatuslabelsController extends Controller * * @param Request $request * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(Request $request) { @@ -78,22 +69,22 @@ class StatuslabelsController extends Controller // create a new model instance $statusLabel = new Statuslabel(); - if (!$request->filled('statuslabel_types')) { + if ($request->missing('statuslabel_types')) { return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]); } $statusType = Statuslabel::getStatuslabelTypesForDB($request->input('statuslabel_types')); // Save the Statuslabel data - $statusLabel->name = Input::get('name'); + $statusLabel->name = $request->input('name'); $statusLabel->user_id = Auth::id(); - $statusLabel->notes = Input::get('notes'); + $statusLabel->notes = $request->input('notes'); $statusLabel->deployable = $statusType['deployable']; $statusLabel->pending = $statusType['pending']; $statusLabel->archived = $statusType['archived']; - $statusLabel->color = Input::get('color'); - $statusLabel->show_in_nav = Input::get('show_in_nav', 0); - $statusLabel->default_label = Input::get('default_label', 0); + $statusLabel->color = $request->input('color'); + $statusLabel->show_in_nav = $request->input('show_in_nav', 0); + $statusLabel->default_label = $request->input('default_label', 0); if ($statusLabel->save()) { @@ -106,8 +97,9 @@ class StatuslabelsController extends Controller /** * Statuslabel update. * - * @param int $statuslabelId + * @param int $statuslabelId * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit($statuslabelId = null) { @@ -129,8 +121,9 @@ class StatuslabelsController extends Controller /** * Statuslabel update form processing page. * - * @param int $statuslabelId + * @param int $statuslabelId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(Request $request, $statuslabelId = null) { @@ -147,15 +140,15 @@ class StatuslabelsController extends Controller // Update the Statuslabel data - $statustype = Statuslabel::getStatuslabelTypesForDB(Input::get('statuslabel_types')); - $statuslabel->name = Input::get('name'); - $statuslabel->notes = Input::get('notes'); + $statustype = Statuslabel::getStatuslabelTypesForDB($request->input('statuslabel_types')); + $statuslabel->name = $request->input('name'); + $statuslabel->notes = $request->input('notes'); $statuslabel->deployable = $statustype['deployable']; $statuslabel->pending = $statustype['pending']; $statuslabel->archived = $statustype['archived']; - $statuslabel->color = Input::get('color'); - $statuslabel->show_in_nav = Input::get('show_in_nav', 0); - $statuslabel->default_label = Input::get('default_label', 0); + $statuslabel->color = $request->input('color'); + $statuslabel->show_in_nav = $request->input('show_in_nav', 0); + $statuslabel->default_label = $request->input('default_label', 0); // Was the asset created? @@ -169,8 +162,9 @@ class StatuslabelsController extends Controller /** * Delete the given Statuslabel. * - * @param int $statuslabelId + * @param int $statuslabelId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($statuslabelId) { diff --git a/app/Http/Controllers/SuppliersController.php b/app/Http/Controllers/SuppliersController.php index e5798353c0..41ff456791 100755 --- a/app/Http/Controllers/SuppliersController.php +++ b/app/Http/Controllers/SuppliersController.php @@ -1,21 +1,9 @@ notes = request('notes'); $supplier->url = $supplier->addhttp(request('url')); $supplier->user_id = Auth::id(); - $supplier = $request->handleImages($supplier,600, public_path().'/uploads/suppliers'); + $supplier = $request->handleImages($supplier); if ($supplier->save()) { @@ -90,12 +81,13 @@ class SuppliersController extends Controller /** * Supplier update. * - * @param int $supplierId + * @param int $supplierId * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit($supplierId = null) { - $this->authorize('edit', Supplier::class); + $this->authorize('update', Supplier::class); // Check if the supplier exists if (is_null($item = Supplier::find($supplierId))) { // Redirect to the supplier page @@ -110,12 +102,13 @@ class SuppliersController extends Controller /** * Supplier update form processing page. * - * @param int $supplierId + * @param int $supplierId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function update($supplierId = null, ImageUploadRequest $request) + public function update($supplierId, ImageUploadRequest $request) { - $this->authorize('edit', Supplier::class); + $this->authorize('update', Supplier::class); // Check if the supplier exists if (is_null($supplier = Supplier::find($supplierId))) { // Redirect to the supplier page @@ -136,7 +129,7 @@ class SuppliersController extends Controller $supplier->email = request('email'); $supplier->url = $supplier->addhttp(request('url')); $supplier->notes = request('notes'); - $supplier = $request->handleImages($supplier,600, public_path().'/uploads/suppliers'); + $supplier = $request->handleImages($supplier); if ($supplier->save()) { return redirect()->route('suppliers.index')->with('success', trans('admin/suppliers/message.update.success')); @@ -149,8 +142,9 @@ class SuppliersController extends Controller /** * Delete the given supplier. * - * @param int $supplierId + * @param int $supplierId * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($supplierId) { diff --git a/app/Http/Controllers/Users/BulkUsersController.php b/app/Http/Controllers/Users/BulkUsersController.php new file mode 100644 index 0000000000..92a01f6283 --- /dev/null +++ b/app/Http/Controllers/Users/BulkUsersController.php @@ -0,0 +1,225 @@ +] + * @since [v1.7] + * @param Request $request + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit(Request $request) + { + $this->authorize('update', User::class); + + // Make sure there were users selected + if (($request->filled('ids')) && (count($request->input('ids')) > 0)) { + // Get the list of affected users + $users = User::whereIn('id', array_keys(request('ids'))) + ->with('groups', 'assets', 'licenses', 'accessories')->get(); + + if ($request->input('bulk_actions') == 'edit') { + return view('users/bulk-edit', compact('users')) + ->with('groups', Group::pluck('name', 'id')); + + } elseif ($request->input('bulk_actions') == 'delete') { + return view('users/confirm-bulk-delete')->with('users', $users)->with('statuslabel_list', Helper::statusLabelList()); + + + } elseif ($request->input('bulk_actions') == 'bulkpasswordreset') { + foreach ($users as $user) { + if (($user->activated=='1') && ($user->email!='')) { + $credentials = ['email' => $user->email]; + Password::sendResetLink($credentials, function (Message $message) { + $message->subject($this->getEmailSubject()); + }); + } + } + return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent')); + + } + + } + + return redirect()->back()->with('error', 'No users selected'); + } + + + /** + * Save bulk-edited users + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param Request $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function update(Request $request) + { + $this->authorize('update', User::class); + + if((!$request->filled('ids')) || $request->input('ids') <= 0) { + return redirect()->back()->with('error', 'No users selected'); + } + $user_raw_array = $request->input('ids'); + + // Remove the user from any updates. + $user_raw_array = array_diff($user_raw_array, [Auth::id()]); + $manager_conflict = false; + $users = User::whereIn('id', $user_raw_array)->where('id', '!=', Auth::user()->id)->get(); + + $return_array = [ + 'success' => trans('admin/users/message.success.update_bulk') + ]; + + + $this->conditionallyAddItem('location_id') + ->conditionallyAddItem('department_id') + ->conditionallyAddItem('company_id') + ->conditionallyAddItem('locale') + ->conditionallyAddItem('activated') +; + // If the manager_id is one of the users being updated, generate a warning. + if (array_search($request->input('manager_id'), $user_raw_array)) { + $manager_conflict = true; + $return_array = [ + 'warning' => trans('admin/users/message.bulk_manager_warn') + ]; + } + if (!$manager_conflict) { + $this->conditionallyAddItem('manager_id'); + } + + + // Save the updated info + User::whereIn('id', $user_raw_array) + ->where('id', '!=', Auth::id())->update($this->update_array); + + // Only sync groups if groups were selected + if ($request->filled('groups')) { + foreach ($users as $user) { + $user->groups()->sync($request->input('groups')); + } + } + + return redirect()->route('users.index') + ->with($return_array); + } + + /** + * Array to store update data per item + * @var Array + */ + private $update_array = []; + + /** + * Adds parameter to update array for an item if it exists in request + * @param String $field field name + * @return BulkUsersController Model for Chaining + */ + protected function conditionallyAddItem($field) + { + if(request()->filled($field)) { + $this->update_array[$field] = request()->input($field); + } + return $this; + } + + /** + * Soft-delete bulk users + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param Request $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy(Request $request) + { + $this->authorize('update', User::class); + + if ((!$request->filled('ids')) || (count($request->input('ids')) == 0)) { + return redirect()->back()->with('error', 'No users selected'); + } + if ((!$request->filled('status_id')) || ($request->input('status_id')=='')) { + return redirect()->route('users.index')->with('error', 'No status selected'); + } + + if (config('app.lock_passwords')) { + return redirect()->route('users.index')->with('error', 'Bulk delete is not enabled in this installation'); + } + $user_raw_array = request('ids'); + + if (($key = array_search(Auth::id(), $user_raw_array)) !== false) { + unset($user_raw_array[$key]); + } + + $users = User::whereIn('id', $user_raw_array)->get(); + $assets = Asset::whereIn('assigned_to', $user_raw_array)->get(); + $accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get(); + $licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get(); + + + $this->logItemCheckinAndDelete($assets, Asset::class); + $this->logItemCheckinAndDelete($accessories, Accessory::class); + $this->logItemCheckinAndDelete($licenses, LicenseSeat::class); + + Asset::whereIn('id', $assets->pluck('id'))->update([ + 'status_id' => e(request('status_id')), + 'assigned_to' => null, + 'assigned_type' => null, + ]); + + + LicenseSeat::whereIn('id', $licenses->pluck('id'))->update(['assigned_to' => null]); + + foreach ($users as $user) { + $user->accessories()->sync([]); + $user->delete(); + } + + return redirect()->route('users.index')->with('success', 'Your selected users have been deleted and their assets have been updated.'); + } + + /** + * Generate an action log entry for each of a group of items. + * @param $items + * @param $itemType string name of items being passed. + */ + protected function logItemCheckinAndDelete($items, $itemType) { + + foreach($items as $item) { + $logAction = new Actionlog(); + $logAction->item_id = $item->id; + // We can't rely on get_class here because the licenses/accessories fetched above are not eloquent models, but simply arrays. + $logAction->item_type = $itemType; + $logAction->target_id = $item->assigned_to; + $logAction->target_type = User::class; + $logAction->user_id = Auth::id(); + $logAction->note = 'Bulk checkin items and delete user'; + $logAction->logaction('checkin from'); + } + } + + + +} diff --git a/app/Http/Controllers/Users/LDAPImportController.php b/app/Http/Controllers/Users/LDAPImportController.php new file mode 100644 index 0000000000..6e2a3091b0 --- /dev/null +++ b/app/Http/Controllers/Users/LDAPImportController.php @@ -0,0 +1,85 @@ +ldap = $ldap; + $this->ldap->init(); + } + + /** + * Return view for LDAP import. + * + * @author Aladin Alaily + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return \Illuminate\Contracts\View\View + * + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create() + { + $this->authorize('update', User::class); + try { + //$this->ldap->connect(); I don't think this actually exists in LdapAd.php, and we don't really 'persist' LDAP connections anyways...right? + } catch (\Exception $e) { + return redirect()->route('users.index')->with('error', $e->getMessage()); + } + + return view('users/ldap'); + } + + /** + * LDAP form processing. + * + * @author Aladin Alaily + * @author A. Gianotto + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return \Illuminate\Http\RedirectResponse + */ + public function store(Request $request) + { + // Call Artisan LDAP import command. + $location_id = $request->input('location_id'); + Artisan::call('snipeit:ldap-sync', ['--location_id' => $location_id, '--json_summary' => true]); + + // Collect and parse JSON summary. + $ldap_results_json = Artisan::output(); + $ldap_results = json_decode($ldap_results_json, true); + + // Direct user to appropriate status page. + if ($ldap_results['error']) { + return redirect()->back()->withInput()->with('error', $ldap_results['error_message']); + } + + return redirect()->route('ldap/user') + ->with('success', 'LDAP Import successful.') + ->with('summary', $ldap_results['summary']); + } +} diff --git a/app/Http/Controllers/Users/UserFilesController.php b/app/Http/Controllers/Users/UserFilesController.php new file mode 100644 index 0000000000..1776a34c3b --- /dev/null +++ b/app/Http/Controllers/Users/UserFilesController.php @@ -0,0 +1,129 @@ +] + * @since [v1.6] + * @param AssetFileRequest $request + * @param int $userId + * @return string JSON + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(AssetFileRequest $request, $userId = null) + { + $user = User::find($userId); + $destinationPath = config('app.private_uploads') . '/users'; + + if (isset($user->id)) { + $this->authorize('update', $user); + + $logActions = []; + $files = $request->file('file'); + foreach($files as $file) { + $extension = $file->getClientOriginalExtension(); + $filename = 'user-' . $user->id . '-' . str_random(8); + $filename .= '-' . str_slug($file->getClientOriginalName()) . '.' . $extension; + if (!$file->move($destinationPath, $filename)) { + return JsonResponse::create(["error" => "Unabled to move file"], 500); + } + //Log the uploaded file to the log + $logAction = new Actionlog(); + $logAction->item_id = $user->id; + $logAction->item_type = User::class; + $logAction->user_id = Auth::id(); + $logAction->note = $request->input('notes'); + $logAction->target_id = null; + $logAction->created_at = date("Y-m-d H:i:s"); + $logAction->filename = $filename; + $logAction->action_type = 'uploaded'; + + if (!$logAction->save()) { + return JsonResponse::create(["error" => "Failed validation: " . print_r($logAction->getErrors(), true)], 500); + + } + $logActions[] = $logAction; + } +// dd($logActions); + return JsonResponse::create($logActions); + } + return JsonResponse::create(["error" => "No User associated with this request"], 500); + + } + + + /** + * Delete file + * + * @author [A. Gianotto] [] + * @since [v1.6] + * @param int $userId + * @param int $fileId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($userId = null, $fileId = null) + { + $user = User::find($userId); + $destinationPath = config('app.private_uploads').'/users'; + + if (isset($user->id)) { + $this->authorize('update', $user); + $log = Actionlog::find($fileId); + $full_filename = $destinationPath . '/' . $log->filename; + if (file_exists($full_filename)) { + unlink($destinationPath . '/' . $log->filename); + } + $log->delete(); + return redirect()->back()->with('success', trans('admin/users/message.deletefile.success')); + } + // Prepare the error message + $error = trans('admin/users/message.user_not_found', ['id' => $userId]); + // Redirect to the licence management page + return redirect()->route('users.index')->with('error', $error); + + } + + /** + * Display/download the uploaded file + * + * @author [A. Gianotto] [] + * @since [v1.6] + * @param int $userId + * @param int $fileId + * @return mixed + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($userId = null, $fileId = null) + { + $user = User::find($userId); + + // the license is valid + if (isset($user->id)) { + $this->authorize('view', $user); + + $log = Actionlog::find($fileId); + $file = $log->get_src('users'); + return Response::download($file); + } + // Prepare the error message + $error = trans('admin/users/message.user_not_found', ['id' => $userId]); + + // Redirect to the licence management page + return redirect()->route('users.index')->with('error', $error); + } + +} diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php new file mode 100755 index 0000000000..bfba9b26f7 --- /dev/null +++ b/app/Http/Controllers/Users/UsersController.php @@ -0,0 +1,620 @@ +] + * @see UsersController::getDatatable() method that generates the JSON response + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index() + { + $this->authorize('index', User::class); + return view('users/index'); + } + + /** + * Returns a view that displays the user creation form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function create(Request $request) + { + $this->authorize('create', User::class); + $groups = Group::pluck('name', 'id'); + + $userGroups = collect(); + + if ($request->old('groups')) { + $userGroups = Group::whereIn('id', $request->old('groups'))->pluck('name', 'id'); + } + + $permissions = config('permissions'); + $userPermissions = Helper::selectedPermissionsArray($permissions, $request->old('permissions', array())); + $permissions = $this->filterDisplayable($permissions); + + $user = new User; + $user->activated = 1; + + return view('users/edit', compact('groups', 'userGroups', 'permissions', 'userPermissions')) + ->with('user', $user); + } + + /** + * Validate and store the new user data, or return an error. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param SaveUserRequest $request + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function store(SaveUserRequest $request) + { + $this->authorize('create', User::class); + $user = new User; + //Username, email, and password need to be handled specially because the need to respect config values on an edit. + $user->email = e($request->input('email')); + $user->username = e($request->input('username')); + if ($request->filled('password')) { + $user->password = bcrypt($request->input('password')); + } + $user->first_name = $request->input('first_name'); + $user->last_name = $request->input('last_name'); + $user->locale = $request->input('locale'); + $user->employee_num = $request->input('employee_num'); + $user->activated = $request->input('activated', 0); + $user->jobtitle = $request->input('jobtitle'); + $user->phone = $request->input('phone'); + $user->location_id = $request->input('location_id', null); + $user->department_id = $request->input('department_id', null); + $user->company_id = Company::getIdForUser($request->input('company_id', null)); + $user->manager_id = $request->input('manager_id', null); + $user->notes = $request->input('notes'); + $user->address = $request->input('address', null); + $user->city = $request->input('city', null); + $user->state = $request->input('state', null); + $user->country = $request->input('country', null); + $user->zip = $request->input('zip', null); + + // Strip out the superuser permission if the user isn't a superadmin + $permissions_array = $request->input('permission'); + + if (!Auth::user()->isSuperUser()) { + unset($permissions_array['superuser']); + } + $user->permissions = json_encode($permissions_array); + + + // we have to invoke the + app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar'); + + if ($user->save()) { + if ($request->filled('groups')) { + $user->groups()->sync($request->input('groups')); + } else { + $user->groups()->sync(array()); + } + + if (($request->input('email_user') == 1) && ($request->filled('email'))) { + // Send the credentials through email + $data = array(); + $data['email'] = e($request->input('email')); + $data['username'] = e($request->input('username')); + $data['first_name'] = e($request->input('first_name')); + $data['last_name'] = e($request->input('last_name')); + $data['password'] = e($request->input('password')); + + $user->notify(new WelcomeNotification($data)); + } + return redirect::route('users.index')->with('success', trans('admin/users/message.success.create')); + } + return redirect()->back()->withInput()->withErrors($user->getErrors()); + } + + + + private function filterDisplayable($permissions) + { + $output = null; + foreach ($permissions as $key => $permission) { + $output[$key] = array_filter($permission, function ($p) { + return $p['display'] === true; + }); + } + return $output; + } + + /** + * Returns a view that displays the edit user form + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param $permissions + * @return View + * @internal param int $id + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit($id) + { + if ($user = User::find($id)) { + $this->authorize('update', $user); + $permissions = config('permissions'); + + $groups = Group::pluck('name', 'id'); + + $userGroups = $user->groups()->pluck('name', 'id'); + $user->permissions = $user->decodePermissions(); + $userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions); + $permissions = $this->filterDisplayable($permissions); + + return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user); + } + + $error = trans('admin/users/message.user_not_found', compact('id')); + return redirect()->route('users.index')->with('error', $error); + } + + /** + * Validate and save edited user data from edit form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param SaveUserRequest $request + * @param int $id + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function update(SaveUserRequest $request, $id = null) + { + + // We need to reverse the UI specific logic for our + // permissions here before we update the user. + $permissions = $request->input('permissions', array()); + app('request')->request->set('permissions', $permissions); + + // 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'))) { + return redirect()->route('users.index')->with('error', 'Permission denied. You cannot update user information for superadmins on the demo.'); + } + + try { + $user = User::findOrFail($id); + } catch (ModelNotFoundException $e) { + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', compact('id'))); + } + + $this->authorize('update', $user); + // Figure out of this user was an admin before this edit + $orig_permissions_array = $user->decodePermissions(); + $orig_superuser = '0'; + if (is_array($orig_permissions_array)) { + if (array_key_exists('superuser', $orig_permissions_array)) { + $orig_superuser = $orig_permissions_array['superuser']; + } + } + + // Only save groups if the user is a super user + if (Auth::user()->isSuperUser()) { + $user->groups()->sync($request->input('groups')); + } + + + // Update the user + if ($request->filled('username')) { + $user->username = $request->input('username'); + } + $user->email = $request->input('email'); + $user->first_name = $request->input('first_name'); + $user->last_name = $request->input('last_name'); + $user->two_factor_optin = $request->input('two_factor_optin') ?: 0; + $user->locale = $request->input('locale'); + $user->employee_num = $request->input('employee_num'); + $user->activated = $request->input('activated', 0); + $user->jobtitle = $request->input('jobtitle', null); + $user->phone = $request->input('phone'); + $user->location_id = $request->input('location_id', null); + $user->company_id = Company::getIdForUser($request->input('company_id', null)); + $user->manager_id = $request->input('manager_id', null); + $user->notes = $request->input('notes'); + $user->department_id = $request->input('department_id', null); + $user->address = $request->input('address', null); + $user->city = $request->input('city', null); + $user->state = $request->input('state', null); + $user->country = $request->input('country', null); + $user->activated = $request->input('activated', 0); + $user->zip = $request->input('zip', null); + + + // 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)]); + + // Do we want to update the user password? + if ($request->filled('password')) { + $user->password = bcrypt($request->input('password')); + } + + $permissions_array = $request->input('permission'); + + // Strip out the superuser permission if the user isn't a superadmin + if (!Auth::user()->isSuperUser()) { + unset($permissions_array['superuser']); + $permissions_array['superuser'] = $orig_superuser; + } + + $user->permissions = json_encode($permissions_array); + + // Handle uploaded avatar + app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); + + + //\Log::debug(print_r($user, true)); + + // Was the user updated? + if ($user->save()) { + // Redirect to the user page + return redirect()->route('users.index') + ->with('success', trans('admin/users/message.success.update')); + } + return redirect()->back()->withInput()->withErrors($user->getErrors()); + } + + /** + * Delete a user + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $id + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function destroy($id = null) + { + try { + // Get user information + $user = User::findOrFail($id); + // Authorize takes care of many of our logic checks now. + $this->authorize('delete', User::class); + + // Check if we are not trying to delete ourselves + if ($user->id === Auth::id()) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', 'We would feel really bad if you deleted yourself, please reconsider.'); + } + + if (($user->assets()) && (($assetsCount = $user->assets()->count()) > 0)) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', 'This user still has ' . $assetsCount . ' assets associated with them.'); + } + + if (($user->licenses()) && (($licensesCount = $user->licenses()->count())) > 0) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', 'This user still has ' . $licensesCount . ' licenses associated with them.'); + } + + if (($user->accessories()) && (($accessoriesCount = $user->accessories()->count()) > 0)) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', 'This user still has ' . $accessoriesCount . ' accessories associated with them.'); + } + + if (($user->managedLocations()) && (($managedLocationsCount = $user->managedLocations()->count())) > 0) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', 'This user still has ' . $managedLocationsCount . ' locations that they manage.'); + } + + // Delete the user + $user->delete(); + + // Prepare the success message + // Redirect to the user management page + return redirect()->route('users.index')->with('success', trans('admin/users/message.success.delete')); + } catch (ModelNotFoundException $e) { + // Prepare the error message + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', compact('id'))); + } + } + + /** + * Restore a deleted user + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $id + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function getRestore($id = null) + { + $this->authorize('update', User::class); + // Get user information + if (!User::onlyTrashed()->find($id)) { + return redirect()->route('users.index')->with('error', trans('admin/users/messages.user_not_found')); + } + + // Restore the user + if (User::withTrashed()->where('id', $id)->restore()) { + return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored')); + } + return redirect()->route('users.index')->with('error', 'User could not be restored.'); + } + + + /** + * Return a view with user detail + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $userId + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function show($userId = null) + { + if (!$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($userId)) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', ['id' => $userId])); + } + + $userlog = $user->userlog->load('item'); + + $this->authorize('view', $user); + return view('users/view', compact('user', 'userlog')) + ->with('settings', Setting::getSettings()); + } + + /** + * Unsuspend a user. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $id + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function getUnsuspend($id = null) + { + try { + // Get user information + $user = User::findOrFail($id); + $this->authorize('update', $user); + + // Check if we are not trying to unsuspend ourselves + if ($user->id === Auth::id()) { + // Prepare the error message + $error = trans('admin/users/message.error.unsuspend'); + // Redirect to the user management page + return redirect()->route('users.index')->with('error', $error); + } + + // Do we have permission to unsuspend this user? + if ($user->isSuperUser() && !Auth::user()->isSuperUser()) { + // Redirect to the user management page + return redirect()->route('users.index')->with('error', 'Insufficient permissions!'); + } + + // Redirect to the user management page + return redirect()->route('users.index')->with('success', trans('admin/users/message.success.unsuspend')); + } catch (ModelNotFoundException $e) { + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', compact('id'))); + } + } + + + /** + * Return a view containing a pre-populated new user form, + * populated with some fields from an existing user. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $id + * @return \Illuminate\Contracts\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function getClone(Request $request, $id = null) + { + $this->authorize('create', User::class); + // We need to reverse the UI specific logic for our + // permissions here before we update the user. + $permissions = $request->input('permissions', array()); + app('request')->request->set('permissions', $permissions); + + + try { + // Get the user information + $user_to_clone = User::withTrashed()->find($id); + $user = clone $user_to_clone; + $user->first_name = ''; + $user->last_name = ''; + $user->email = substr($user->email, ($pos = strpos($user->email, '@')) !== false ? $pos : 0); + + $user->id = null; + + // Get this user groups + $userGroups = $user_to_clone->groups()->pluck('name', 'id'); + // Get all the available permissions + $permissions = config('permissions'); + $clonedPermissions = $user_to_clone->decodePermissions(); + + $userPermissions = Helper::selectedPermissionsArray($permissions, $clonedPermissions); + + // Show the page + return view('users/edit', compact('permissions', 'userPermissions')) + ->with('user', $user) + ->with('groups', Group::pluck('name', 'id')) + ->with('userGroups', $userGroups) + ->with('clone_user', $user_to_clone); + } catch (ModelNotFoundException $e) { + // Prepare the error message + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', compact('id'))); + } + } + + + /** + * Exports users to CSV + * + * @author [A. Gianotto] [] + * @since [v3.5] + * @return StreamedResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function getExportUserCsv() + { + $this->authorize('view', User::class); + \Debugbar::disable(); + + $response = new StreamedResponse(function () { + // Open output stream + $handle = fopen('php://output', 'w'); + + User::with('assets', 'accessories', 'consumables', 'department', 'licenses', 'manager', 'groups', 'userloc', 'company') + ->orderBy('created_at', 'DESC') + ->chunk(500, function ($users) use ($handle) { + $headers=[ + // strtolower to prevent Excel from trying to open it as a SYLK file + strtolower(trans('general.id')), + trans('admin/companies/table.title'), + trans('admin/users/table.title'), + trans('admin/users/table.employee_num'), + trans('admin/users/table.name'), + trans('admin/users/table.username'), + trans('admin/users/table.email'), + trans('admin/users/table.manager'), + trans('admin/users/table.location'), + trans('general.department'), + trans('general.assets'), + trans('general.licenses'), + trans('general.accessories'), + trans('general.consumables'), + trans('admin/users/table.groups'), + trans('general.notes'), + trans('admin/users/table.activated'), + trans('general.created_at') + ]; + + fputcsv($handle, $headers); + + foreach ($users as $user) { + $user_groups = ''; + + foreach ($user->groups as $user_group) { + $user_groups .= $user_group->name.', '; + } + + // Add a new row with data + $values = [ + $user->id, + ($user->company) ? $user->company->name : '', + $user->jobtitle, + $user->employee_num, + $user->present()->fullName(), + $user->username, + $user->email, + ($user->manager) ? $user->manager->present()->fullName() : '', + ($user->userloc) ? $user->userloc->name : '', + ($user->department) ? $user->department->name : '', + $user->assets->count(), + $user->licenses->count(), + $user->accessories->count(), + $user->consumables->count(), + $user_groups, + $user->notes, + ($user->activated=='1') ? trans('general.yes') : trans('general.no'), + $user->created_at, + ]; + + fputcsv($handle, $values); + } + }); + + // Close the output stream + fclose($handle); + }, 200, [ + 'Content-Type' => 'text/csv; charset=UTF-8', + 'Content-Disposition' => 'attachment; filename="users-'.date('Y-m-d-his').'.csv"', + ]); + + return $response; + } + + /** + * LDAP form processing. + * + * @author Aladin Alaily + * @since [v1.8] + * @return \Illuminate\Http\RedirectResponse + */ + public function printInventory($id) + { + $this->authorize('view', User::class); + $show_user = User::where('id', $id)->withTrashed()->first(); + $assets = Asset::where('assigned_to', $id)->where('assigned_type', User::class)->with('model', 'model.category')->get(); + $accessories = $show_user->accessories()->get(); + $consumables = $show_user->consumables()->get(); + return view('users/print')->with('assets', $assets) + ->with('licenses', $show_user->licenses()->get()) + ->with('accessories', $accessories) + ->with('consumables', $consumables) + ->with('show_user', $show_user) + ->with('settings', Setting::getSettings()); + } +} diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php deleted file mode 100755 index 79d1e2925b..0000000000 --- a/app/Http/Controllers/UsersController.php +++ /dev/null @@ -1,1012 +0,0 @@ -] - * @see UsersController::getDatatable() method that generates the JSON response - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function index() - { - $this->authorize('index', User::class); - return view('users/index'); - } - - /** - * Returns a view that displays the user creation form. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return \Illuminate\Contracts\View\View - */ - public function create() - { - $this->authorize('create', User::class); - $groups = Group::pluck('name', 'id'); - - if (Input::old('groups')) { - $userGroups = Group::whereIn('id', Input::old('groups'))->pluck('name', 'id'); - } else { - $userGroups = collect(); - } - - $permissions = config('permissions'); - $userPermissions = Helper::selectedPermissionsArray($permissions, Input::old('permissions', array())); - $permissions = $this->filterDisplayable($permissions); - - $user = new User; - $user->activated = 1; - - return view('users/edit', compact('groups', 'userGroups', 'permissions', 'userPermissions')) - ->with('user', $user); - } - - /** - * Validate and store the new user data, or return an error. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function store(SaveUserRequest $request) - { - $this->authorize('create', User::class); - $user = new User; - //Username, email, and password need to be handled specially because the need to respect config values on an edit. - $user->email = $data['email'] = e($request->input('email')); - $user->username = $data['username'] = e($request->input('username')); - if ($request->filled('password')) { - $user->password = bcrypt($request->input('password')); - $data['password'] = $request->input('password'); - } - $user->first_name = $request->input('first_name'); - $user->last_name = $request->input('last_name'); - $user->locale = $request->input('locale'); - $user->employee_num = $request->input('employee_num'); - $user->activated = $request->input('activated', 0); - $user->jobtitle = $request->input('jobtitle'); - $user->phone = $request->input('phone'); - $user->location_id = $request->input('location_id', null); - $user->department_id = $request->input('department_id', null); - $user->company_id = Company::getIdForUser($request->input('company_id', null)); - $user->manager_id = $request->input('manager_id', null); - $user->notes = $request->input('notes'); - $user->address = $request->input('address', null); - $user->city = $request->input('city', null); - $user->state = $request->input('state', null); - $user->country = $request->input('country', null); - $user->zip = $request->input('zip', null); - - // Strip out the superuser permission if the user isn't a superadmin - $permissions_array = $request->input('permission'); - - if (!Auth::user()->isSuperUser()) { - unset($permissions_array['superuser']); - } - $user->permissions = json_encode($permissions_array); - - if ($user->save()) { - - if ($request->filled('groups')) { - $user->groups()->sync($request->input('groups')); - } else { - $user->groups()->sync(array()); - } - - if (($request->input('email_user') == 1) && ($request->filled('email'))) { - // Send the credentials through email - $data = array(); - $data['email'] = e($request->input('email')); - $data['username'] = e($request->input('username')); - $data['first_name'] = e($request->input('first_name')); - $data['last_name'] = e($request->input('last_name')); - $data['password'] = e($request->input('password')); - - $user->notify(new WelcomeNotification($data)); - -/* Mail::send('emails.send-login', $data, function ($m) use ($user) { - $m->to($user->email, $user->first_name . ' ' . $user->last_name); - $m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name')); - $m->subject(trans('mail.welcome', ['name' => $user->first_name])); - });*/ - } - return redirect::route('users.index')->with('success', trans('admin/users/message.success.create')); - } - return redirect()->back()->withInput()->withErrors($user->getErrors()); - } - - - - private function filterDisplayable($permissions) - { - $output = null; - foreach ($permissions as $key => $permission) { - $output[$key] = array_filter($permission, function ($p) { - return $p['display'] === true; - }); - } - return $output; - } - - /** - * Returns a view that displays the edit user form - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param $permissions - * @return View - * @internal param int $id - */ - public function edit($id) - { - - if ($user = User::find($id)) { - - $this->authorize('update', $user); - $permissions = config('permissions'); - - $groups = Group::pluck('name', 'id'); - - $userGroups = $user->groups()->pluck('name', 'id'); - $user->permissions = $user->decodePermissions(); - $userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions); - $permissions = $this->filterDisplayable($permissions); - - return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user); - } - - $error = trans('admin/users/message.user_not_found', compact('id')); - return redirect()->route('users.index')->with('error', $error); - - - } - - /** - * Validate and save edited user data from edit form. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param UpdateUserRequest $request - * @param int $id - * @return \Illuminate\Http\RedirectResponse - */ - public function update(SaveUserRequest $request, $id = null) - { - // We need to reverse the UI specific logic for our - // permissions here before we update the user. - $permissions = $request->input('permissions', array()); - app('request')->request->set('permissions', $permissions); - // Only update the email address if locking is set to false - if (config('app.lock_passwords')) { - return redirect()->route('users.index')->with('error', 'Denied! You cannot update user information on the demo.'); - } - - try { - - $user = User::find($id); - - if ($user->id == $request->input('manager_id')) { - return redirect()->back()->withInput()->with('error', 'You cannot be your own manager.'); - } - - // If the user isn't a superuser, don't let them edit their own permissions - if ((!Auth::user()->isSuperUser()) && ($user->id == Auth::user()->id)) { - return redirect()->back()->withInput()->with('error', 'You cannot edit your own permissions. Please contact an administrator.'); - } - - $this->authorize('update', $user); - // Figure out of this user was an admin before this edit - $orig_permissions_array = $user->decodePermissions(); - $orig_superuser = '0'; - if (is_array($orig_permissions_array)) { - if (array_key_exists('superuser', $orig_permissions_array)) { - $orig_superuser = $orig_permissions_array['superuser']; - } - } - - - } catch (ModelNotFoundException $e) { - return redirect()->route('users.index') - ->with('error', trans('admin/users/message.user_not_found', compact('id'))); - } - - - // Only save groups if the user is a super user - if (Auth::user()->isSuperUser()) { - $user->groups()->sync($request->input('groups')); - } - - - if ($request->filled('username')) { - $user->username = $request->input('username'); - } - $user->email = $request->input('email'); - - - // Update the user - $user->first_name = $request->input('first_name'); - $user->last_name = $request->input('last_name'); - $user->two_factor_optin = $request->input('two_factor_optin') ?: 0; - $user->locale = $request->input('locale'); - $user->employee_num = $request->input('employee_num'); - $user->activated = $request->input('activated', 0); - $user->jobtitle = $request->input('jobtitle', null); - $user->phone = $request->input('phone'); - $user->website = $request->input('website', null); - $user->location_id = $request->input('location_id', null); - $user->company_id = Company::getIdForUser($request->input('company_id', null)); - $user->manager_id = $request->input('manager_id', null); - $user->notes = $request->input('notes'); - $user->department_id = $request->input('department_id', null); - $user->address = $request->input('address', null); - $user->city = $request->input('city', null); - $user->state = $request->input('state', null); - $user->country = $request->input('country', null); - $user->activated = $request->input('activated', 0); - $user->zip = $request->input('zip', null); - - - // 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)]); - - // Do we want to update the user password? - if ($request->filled('password')) { - $user->password = bcrypt($request->input('password')); - } - - // Strip out the superuser permission if the user isn't a superadmin - $permissions_array = $request->input('permission'); - - if (!Auth::user()->isSuperUser()) { - unset($permissions_array['superuser']); - $permissions_array['superuser'] = $orig_superuser; - } - - $user->permissions = json_encode($permissions_array); - - // Was the user updated? - if ($user->save()) { - // Prepare the success message - $success = trans('admin/users/message.success.update'); - // Redirect to the user page - return redirect()->route('users.index')->with('success', $success); - } - return redirect()->back()->withInput()->withErrors($user->getErrors()); - } - - /** - * Delete a user - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $id - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy($id = null) - { - try { - // Get user information - $user = User::findOrFail($id); - // Authorize takes care of many of our logic checks now. - $this->authorize('delete', User::class); - - // Check if we are not trying to delete ourselves - if ($user->id === Auth::user()->id) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'You cannot delete yourself.'); - } - - if (($user->assets) && ($user->assets->count() > 0)) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets->count() . ' assets associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.'); - } - - if (($user->licenses) && ($user->licenses->count() > 0)) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'This user still has ' . $user->licenses->count() . ' license(s associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.'); - } - - if (($user->accessories) && ($user->accessories->count() > 0)) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'This user still has ' . $user->accessories->count() . ' accessories associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.'); - } - - if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.'); - } - - // Delete the user - $user->delete(); - - // Prepare the success message - $success = trans('admin/users/message.success.delete'); - - // Redirect to the user management page - return redirect()->route('users.index')->with('success', $success); - } catch (ModelNotFoundException $e) { - // Prepare the error message - $error = trans('admin/users/message.user_not_found', compact('id')); - // Redirect to the user management page - return redirect()->route('users.index')->with('error', $error); - } - } - - /** - * Returns a view that confirms the user's a bulk delete will be applied to. - * - * @author [A. Gianotto] [] - * @since [v1.7] - * @return \Illuminate\Contracts\View\View - */ - public function postBulkEdit(Request $request) - { - $this->authorize('update', User::class); - - if (($request->filled('ids')) && (count($request->input('ids')) > 0)) { - $statuslabel_list = Helper::statusLabelList(); - $user_raw_array = array_keys(Input::get('ids')); - $users = User::whereIn('id', $user_raw_array)->with('groups', 'assets', 'licenses', 'accessories')->get(); - if ($request->input('bulk_actions') == 'edit') { - return view('users/bulk-edit', compact('users')) - ->with('groups', Group::pluck('name', 'id')); - } - return view('users/confirm-bulk-delete', compact('users', 'statuslabel_list')); - } - - return redirect()->back()->with('error', 'No users selected'); - } - - - /** - * Save bulk-edited users - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function postBulkEditSave(Request $request) - { - $this->authorize('update', User::class); - - if (($request->filled('ids')) && (count($request->input('ids')) > 0)) { - - $user_raw_array = $request->input('ids'); - $update_array = array(); - $manager_conflict = false; - $users = User::whereIn('id', $user_raw_array)->where('id', '!=', Auth::user()->id)->get(); - - if ($request->filled('location_id')) { - $update_array['location_id'] = $request->input('location_id'); - } - if ($request->filled('department_id')) { - $update_array['department_id'] = $request->input('department_id'); - } - if ($request->filled('city')) { - $update_array['city'] = $request->input('city'); - } - - if ($request->filled('company_id')) { - $update_array['company_id'] = $request->input('company_id'); - } - if ($request->filled('locale')) { - $update_array['locale'] = $request->input('locale'); - } - - - if ($request->filled('manager_id')) { - - // Do not allow a manager update if the selected manager is one of the users being - // edited. - if (!array_key_exists($request->input('manager_id'), $user_raw_array)) { - $update_array['manager_id'] = $request->input('manager_id'); - } else { - $manager_conflict = true; - } - - } - if ($request->filled('activated')) { - $update_array['activated'] = $request->input('activated'); - } - - // Save the updated info - if (count($update_array) > 0) { - User::whereIn('id', $user_raw_array)->where('id', '!=', Auth::user()->id)->update($update_array); - } - - // Only sync groups if groups were selected - if ($request->filled('groups')) { - foreach ($users as $user) { - $user->groups()->sync($request->input('groups')); - } - } - - if ($manager_conflict) { - return redirect()->route('users.index') - ->with('warning', trans('admin/users/message.bulk_manager_warn')); - } - - return redirect()->route('users.index') - ->with('success', trans('admin/users/message.success.update_bulk')); - } - - return redirect()->back()->with('error', 'No users selected'); - - - - } - - /** - * Soft-delete bulk users - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @return \Illuminate\Http\RedirectResponse - */ - public function postBulkSave(Request $request) - { - $this->authorize('update', User::class); - - if ((!$request->filled('ids')) || (count($request->input('ids')) == 0)) { - return redirect()->back()->with('error', 'No users selected'); - } elseif ((!$request->filled('status_id')) || ($request->input('status_id')=='')) { - return redirect()->route('users.index')->with('error', 'No status selected'); - } else { - - $user_raw_array = Input::get('ids'); - $asset_array = array(); - - if (($key = array_search(Auth::user()->id, $user_raw_array)) !== false) { - unset($user_raw_array[$key]); - } - - - if (!config('app.lock_passwords')) { - - $users = User::whereIn('id', $user_raw_array)->get(); - $assets = Asset::whereIn('assigned_to', $user_raw_array)->get(); - $accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get(); - $licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get(); - $license_array = array(); - $accessory_array = array(); - - foreach ($assets as $asset) { - - $asset_array[] = $asset->id; - - // Update the asset log - $logAction = new Actionlog(); - $logAction->item_id = $asset->id; - $logAction->item_type = Asset::class; - $logAction->target_id = $asset->assigned_to; - $logAction->target_type = User::class; - $logAction->user_id = Auth::user()->id; - $logAction->note = 'Bulk checkin asset and delete user'; - $logAction->logaction('checkin from'); - - Asset::whereIn('id', $asset_array)->update([ - 'status_id' => e(Input::get('status_id')), - 'assigned_to' => null, - ]); - } - - foreach ($accessories as $accessory) { - $accessory_array[] = $accessory->accessory_id; - // Update the asset log - $logAction = new Actionlog(); - $logAction->item_id = $accessory->id; - $logAction->item_type = Accessory::class; - $logAction->target_id = $accessory->assigned_to; - $logAction->target_type = User::class; - $logAction->user_id = Auth::user()->id; - $logAction->note = 'Bulk checkin accessory and delete user'; - $logAction->logaction('checkin from'); - } - - foreach ($licenses as $license) { - $license_array[] = $license->id; - // Update the asset log - $logAction = new Actionlog(); - $logAction->item_id = $license->id; - $logAction->item_type = License::class; - $logAction->target_id = $license->assigned_to; - $logAction->target_type = User::class; - $logAction->user_id = Auth::user()->id; - $logAction->note = 'Bulk checkin license and delete user'; - $logAction->logaction('checkin from'); - } - - LicenseSeat::whereIn('id', $license_array)->update(['assigned_to' => null]); - - foreach ($users as $user) { - $user->accessories()->sync(array()); - $user->delete(); - } - - return redirect()->route('users.index')->with('success', 'Your selected users have been deleted and their assets have been updated.'); - } - return redirect()->route('users.index')->with('error', 'Bulk delete is not enabled in this installation'); - } - } - - /** - * Restore a deleted user - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $id - * @return \Illuminate\Http\RedirectResponse - */ - public function getRestore($id = null) - { - $this->authorize('edit', User::class); - // Get user information - if (!$user = User::onlyTrashed()->find($id)) { - return redirect()->route('users.index')->with('error', trans('admin/users/messages.user_not_found')); - } - - // Restore the user - if (User::withTrashed()->where('id', $id)->restore()) { - return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored')); - } - return redirect()->route('users.index')->with('error', 'User could not be restored.'); - } - - - /** - * Return a view with user detail - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $userId - * @return \Illuminate\Contracts\View\View - */ - public function show($userId = null) - { - if (!$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc') - ->withTrashed() - ->find($userId)) - { - - return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', ['id' => $userId])); - } - - $userlog = $user->userlog->load('item'); - - if (isset($user->id)) { - $this->authorize('view', $user); - return view('users/view', compact('user', 'userlog')); - } - } - - /** - * Unsuspend a user. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $id - * @return Redirect - */ - public function getUnsuspend($id = null) - { - try { - // Get user information - $user = User::find($id); - $this->authorize('edit', $user); - - // Check if we are not trying to unsuspend ourselves - if ($user->id === Auth::user()->id) { - // Prepare the error message - $error = trans('admin/users/message.error.unsuspend'); - // Redirect to the user management page - return redirect()->route('users.index')->with('error', $error); - } - - // Do we have permission to unsuspend this user? - if ($user->isSuperUser() && !Auth::user()->isSuperUser()) { - // Redirect to the user management page - return redirect()->route('users.index')->with('error', 'Insufficient permissions!'); - } - - // Prepare the success message - $success = trans('admin/users/message.success.unsuspend'); - // Redirect to the user management page - return redirect()->route('users.index')->with('success', $success); - } catch (UserNotFoundException $e) { - // Prepare the error message - $error = trans('admin/users/message.user_not_found', compact('id')); - // Redirect to the user management page - return redirect()->route('users.index')->with('error', $error); - } - } - - - /** - * Return a view containing a pre-populated new user form, - * populated with some fields from an existing user. - * - * @author [A. Gianotto] [] - * @since [v1.0] - * @param int $id - * @return \Illuminate\Contracts\View\View - */ - public function getClone($id = null) - { - $this->authorize('create', User::class); - // We need to reverse the UI specific logic for our - // permissions here before we update the user. - $permissions = Input::get('permissions', array()); - //$this->decodePermissions($permissions); - app('request')->request->set('permissions', $permissions); - - - try { - // Get the user information - $user_to_clone = User::withTrashed()->find($id); - $user = clone $user_to_clone; - $user->first_name = ''; - $user->last_name = ''; - $user->email = substr($user->email, ($pos = strpos($user->email, '@')) !== false ? $pos : 0); - - $user->id = null; - - // Get this user groups - $userGroups = $user_to_clone->groups()->pluck('name', 'id'); - // Get all the available permissions - $permissions = config('permissions'); - $clonedPermissions = $user_to_clone->decodePermissions(); - - $userPermissions =Helper::selectedPermissionsArray($permissions, $clonedPermissions); - - // Show the page - return view('users/edit', compact('permissions', 'userPermissions')) - ->with('user', $user) - ->with('groups', Group::pluck('name', 'id')) - ->with('userGroups', $userGroups) - ->with('clone_user', $user_to_clone); - } catch (UserNotFoundException $e) { - - return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found')); - } - } - - /** - * Return JSON response with a list of user details for the getIndex() view. - * - * @author [A. Gianotto] [] - * @since [v1.6] - * @param AssetFileRequest $request - * @param int $userId - * @return string JSON - */ - public function postUpload(AssetFileRequest $request, $userId = null) - { - - $user = User::find($userId); - $destinationPath = config('app.private_uploads') . '/users'; - - if (isset($user->id)) { - $this->authorize('update', $user); - - if (!$request->has('file')) { - \Log::debug('No file selected: '); - \Log::debug(print_r($request, true)); - return redirect()->back()->with('error', 'No file submitted.'); - - } else { - foreach ($request->file('file') as $file) { - - $extension = $file->getClientOriginalExtension(); - $filename = 'user-' . $user->id . '-' . str_random(8); - $filename .= '-' . str_slug($file->getClientOriginalName()) . '.' . $extension; - $upload_success = $file->move($destinationPath, $filename); - - //Log the uploaded file to the log - $logAction = new Actionlog(); - $logAction->item_id = $user->id; - $logAction->item_type = User::class; - $logAction->target_type = User::class; - $logAction->target_id = $user->id; - $logAction->user_id = Auth::user()->id; - $logAction->note = $request->input('notes'); - $logAction->created_at = date("Y-m-d H:i:s"); - $logAction->filename = $filename; - $logAction->action_type = 'uploaded'; - $logAction->save(); - - } - return redirect()->back()->with('success', 'File uploaded'); - } - - } - return redirect()->route('users.index')->with('error', 'Error uploading files'); - } - - - /** - * Delete file - * - * @author [A. Gianotto] [] - * @since [v1.6] - * @param int $userId - * @param int $fileId - * @return \Illuminate\Http\RedirectResponse - */ - public function getDeleteFile($userId = null, $fileId = null) - { - $user = User::find($userId); - $destinationPath = config('app.private_uploads').'/users'; - - if (isset($user->id)) { - $this->authorize('update', $user); - $log = Actionlog::find($fileId); - $full_filename = $destinationPath . '/' . $log->filename; - if (file_exists($full_filename)) { - unlink($destinationPath . '/' . $log->filename); - } - $log->delete(); - return redirect()->back()->with('success', trans('admin/users/message.deletefile.success')); - } - - return redirect()->route('users.index')->with('error', trans('admin/users/message.does_not_exist')); - - } - - /** - * Display/download the uploaded file - * - * @author [A. Gianotto] [] - * @since [v1.6] - * @param int $userId - * @param int $fileId - * @return mixed - */ - public function displayFile($userId = null, $fileId = null) - { - $user = User::find($userId); - - // the license is valid - if (isset($user->id)) { - $this->authorize('view', $user); - - $log = Actionlog::find($fileId); - $file = $log->get_src('users'); - return Response::download($file); - } - // Prepare the error message - $error = trans('admin/users/message.does_not_exist', compact('id')); - - // Redirect to the licence management page - return redirect()->route('users.index')->with('error', $error); - } - - /** - * Return view for LDAP import - * - * @author Aladin Alaily - * @since [v1.8] - * @return \Illuminate\Contracts\View\View - */ - public function getLDAP() - { - $this->authorize('update', User::class); - try { - $ldapconn = Ldap::connectToLdap(); - } catch (\Exception $e) { - return redirect()->route('users.index')->with('error', $e->getMessage()); - } - - try { - Ldap::bindAdminToLdap($ldapconn); - } catch (\Exception $e) { - return redirect()->route('users.index')->with('error', $e->getMessage()); - } - - return view('users/ldap'); - } - - - /** - * Declare the rules for the ldap fields validation. - * - * @author Aladin Alaily - * @since [v1.8] - * @var array - * @deprecated 3.0 - * @todo remove this method in favor of other validation - * @var array - */ - - protected $ldapValidationRules = array( - 'firstname' => 'required|string|min:2', - 'employee_number' => 'string', - 'username' => 'required|min:2|unique:users,username', - 'email' => 'email|unique:users,email', - ); - - /** - * LDAP form processing. - * - * @author Aladin Alaily - * @since [v1.8] - * @return \Illuminate\Http\RedirectResponse - */ - public function postLDAP(Request $request) - { - // Call Artisan LDAP import command. - $location_id = $request->input('location_id'); - Artisan::call('snipeit:ldap-sync', ['--location_id' => $location_id, '--json_summary' => true]); - - // Collect and parse JSON summary. - $ldap_results_json = Artisan::output(); - $ldap_results = json_decode($ldap_results_json, true); - - // Direct user to appropriate status page. - if ($ldap_results['error']) { - return redirect()->back()->withInput()->with('error', $ldap_results['error_message']); - } else { - return redirect()->route('ldap/user')->with('success', "LDAP Import successful.")->with('summary', $ldap_results['summary']); - } - } - - - /** - * Exports users to CSV - * - * @author [A. Gianotto] [] - * @since [v3.5] - * @return StreamedResponse - */ - public function getExportUserCsv() - { - - $this->authorize('view', User::class); - \Debugbar::disable(); - - $response = new StreamedResponse(function () { - // Open output stream - $handle = fopen('php://output', 'w'); - - User::with('assets', 'accessories', 'consumables', 'department', 'licenses', 'manager', 'groups', 'userloc', 'company','throttle')->orderBy('created_at', 'DESC')->chunk(500, function($users) use($handle) { - $headers=[ - // strtolower to prevent Excel from trying to open it as a SYLK file - strtolower(trans('general.id')), - trans('admin/companies/table.title'), - trans('admin/users/table.title'), - trans('admin/users/table.employee_num'), - trans('admin/users/table.name'), - trans('admin/users/table.username'), - trans('admin/users/table.email'), - trans('admin/users/table.manager'), - trans('admin/users/table.location'), - trans('general.department'), - trans('general.assets'), - trans('general.licenses'), - trans('general.accessories'), - trans('general.consumables'), - trans('admin/users/table.groups'), - trans('general.notes'), - trans('admin/users/table.activated'), - trans('general.created_at') - ]; - - fputcsv($handle, $headers); - - foreach ($users as $user) { - $user_groups = ''; - - foreach ($user->groups as $user_group) { - $user_groups .= $user_group->name.', '; - } - - // Add a new row with data - $values = [ - $user->id, - ($user->company) ? $user->company->name : '', - $user->jobtitle, - $user->employee_num, - $user->present()->fullName(), - $user->username, - $user->email, - ($user->manager) ? $user->manager->present()->fullName() : '', - ($user->userloc) ? $user->userloc->name : '', - ($user->department) ? $user->department->name : '', - $user->assets->count(), - $user->licenses->count(), - $user->accessories->count(), - $user->consumables->count(), - $user_groups, - $user->notes, - ($user->activated=='1') ? trans('general.yes') : trans('general.no'), - $user->created_at, - - ]; - - fputcsv($handle, $values); - } - }); - - // Close the output stream - fclose($handle); - }, 200, [ - 'Content-Type' => 'text/csv', - 'Content-Disposition' => 'attachment; filename="users-'.date('Y-m-d-his').'.csv"', - ]); - - return $response; - - } - - /** - * LDAP form processing. - * - * @author Aladin Alaily - * @since [v1.8] - * @return \Illuminate\Http\RedirectResponse - */ - public function printInventory($id) - { - $this->authorize('view', User::class); - $show_user = User::where('id',$id)->withTrashed()->first(); - $assets = Asset::where('assigned_to', $id)->where('assigned_type', User::class)->with('model', 'model.category')->get(); - $licenses = $show_user->licenses()->get(); - $accessories = $show_user->accessories()->get(); - $consumables = $show_user->consumables()->get(); - return view('users/print')->with('assets', $assets)->with('licenses',$licenses)->with('accessories', $accessories)->with('consumables', $consumables)->with('show_user', $show_user); - - } - -} diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php index 0f72f10d2b..37bc95b590 100755 --- a/app/Http/Controllers/ViewAssetsController.php +++ b/app/Http/Controllers/ViewAssetsController.php @@ -1,30 +1,17 @@ userlog->load('item', 'user', 'target'); if (isset($user->id)) { - return view('account/view-assets', compact('user', 'userlog')); + return view('account/view-assets', compact('user', 'userlog')) + ->with('settings', Setting::getSettings()); } else { - // Prepare the error message - $error = trans('admin/users/message.user_not_found', compact('id')); - // Redirect to the user management page - return redirect()->route('users.index')->with('error', $error); + return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id'))); } + // Redirect to the user management page + return redirect()->route('users.index') + ->with('error', trans('admin/users/message.user_not_found', $user->id)); } + /** + * Returns view of requestable items for a user. + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ public function getRequestableIndex() { @@ -78,7 +70,7 @@ class ViewAssetsController extends Controller - public function getRequestItem($itemType, $itemId = null) + public function getRequestItem(Request $request, $itemType, $itemId = null) { $item = null; $fullItemType = 'App\\Models\\' . studly_case($itemType); @@ -102,7 +94,7 @@ class ViewAssetsController extends Controller $logaction->target_id = $data['user_id'] = Auth::user()->id; $logaction->target_type = User::class; - $data['item_quantity'] = Input::has('request-quantity') ? e(Input::get('request-quantity')) : 1; + $data['item_quantity'] = $request->has('request-quantity') ? e($request->input('request-quantity')) : 1; $data['requested_by'] = $user->present()->fullName(); $data['item'] = $item; $data['item_type'] = $itemType; @@ -124,7 +116,7 @@ class ViewAssetsController extends Controller $logaction->logaction('request_canceled'); if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) { - $settings->notify(new RequestAssetCancelationNotification($data)); + $settings->notify(new RequestAssetCancelation($data)); } return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.canceled')); @@ -143,10 +135,11 @@ class ViewAssetsController extends Controller } - - - - + /** + * Process a specific requested asset + * @param null $assetId + * @return \Illuminate\Http\RedirectResponse + */ public function getRequestAsset($assetId = null) { @@ -156,7 +149,8 @@ class ViewAssetsController extends Controller if (is_null($asset = Asset::RequestableAssets()->find($assetId))) { return redirect()->route('requestable-assets') ->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable')); - } elseif (!Company::isCurrentUserHasAccess($asset)) { + } + if (!Company::isCurrentUserHasAccess($asset)) { return redirect()->route('requestable-assets') ->with('error', trans('general.insufficient_permissions')); } @@ -184,20 +178,19 @@ class ViewAssetsController extends Controller $asset->decrement('requests_counter', 1); $logaction->logaction('request canceled'); - $settings->notify(new RequestAssetCancelationNotification($data)); + $settings->notify(new RequestAssetCancelation($data)); return redirect()->route('requestable-assets') ->with('success')->with('success', trans('admin/hardware/message.requests.cancel-success')); - } else { - - $logaction->logaction('requested'); - $asset->request(); - $asset->increment('requests_counter', 1); - $settings->notify(new RequestAssetNotification($data)); - - - return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success')); } + $logaction->logaction('requested'); + $asset->request(); + $asset->increment('requests_counter', 1); + $settings->notify(new RequestAssetNotification($data)); + + + return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success')); + } @@ -259,7 +252,7 @@ class ViewAssetsController extends Controller return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted')); } - if (!Input::has('asset_acceptance')) { + if ($request->missing('asset_acceptance')) { return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline')); } @@ -281,7 +274,7 @@ class ViewAssetsController extends Controller $logaction = new Actionlog(); - if (Input::get('asset_acceptance')=='accepted') { + if ($request->input('asset_acceptance')=='accepted') { $logaction_msg = 'accepted'; $accepted="accepted"; $return_msg = trans('admin/users/message.accepted'); @@ -295,7 +288,7 @@ class ViewAssetsController extends Controller // Asset if (($findlog->item_id!='') && ($findlog->item_type==Asset::class)) { - if (Input::get('asset_acceptance')!='accepted') { + if ($request->input('asset_acceptance')!='accepted') { DB::table('assets') ->where('id', $findlog->item_id) ->update(array('assigned_to' => null)); @@ -304,7 +297,7 @@ class ViewAssetsController extends Controller $logaction->target_id = $findlog->target_id; $logaction->target_type = User::class; - $logaction->note = e(Input::get('note')); + $logaction->note = e($request->input('note')); $logaction->updated_at = date("Y-m-d H:i:s"); diff --git a/app/Http/Middleware/CheckForDebug.php b/app/Http/Middleware/CheckForDebug.php index ff78fd31ba..923b76b1c6 100644 --- a/app/Http/Middleware/CheckForDebug.php +++ b/app/Http/Middleware/CheckForDebug.php @@ -2,8 +2,8 @@ namespace App\Http\Middleware; -use Closure; use Auth; +use Closure; class CheckForDebug { diff --git a/app/Http/Middleware/CheckForSetup.php b/app/Http/Middleware/CheckForSetup.php index e161a912d2..4cf7e72424 100644 --- a/app/Http/Middleware/CheckForSetup.php +++ b/app/Http/Middleware/CheckForSetup.php @@ -2,19 +2,18 @@ namespace App\Http\Middleware; -use Closure; -use Config; -use Route; -use Schema; -use App\Models\User; use App\Models\Setting; +use Closure; class CheckForSetup { public function handle($request, Closure $next, $guard = null) { - // This is dumb + /** + * This is dumb + * @todo Check on removing this, not sure if it's still needed + */ if ($request->is('_debugbar*')) { return $next($request); } diff --git a/app/Http/Middleware/CheckForTwoFactor.php b/app/Http/Middleware/CheckForTwoFactor.php index 61dcf52690..4cf7e265cc 100644 --- a/app/Http/Middleware/CheckForTwoFactor.php +++ b/app/Http/Middleware/CheckForTwoFactor.php @@ -1,52 +1,55 @@ route()->getName()=='two-factor') || ($request->route()->getName()=='two-factor-enroll') || ($request->route()->getPrefix()=='setup') || ($request->route()->getName()=='logout')) { + if (in_array($request->route()->getName(), self::IGNORE_ROUTES)) { return $next($request); } // Two-factor is enabled (either optional or required) - if (Setting::getSettings()) { - if (Auth::check() && (Setting::getSettings()->two_factor_enabled!='')) { - + if ($settings = Setting::getSettings()) { + if (Auth::check() && ($settings->two_factor_enabled != '')) { // This user is already 2fa-authed if ($request->session()->get('2fa_authed')) { return $next($request); } // Two-factor is optional and the user has NOT opted in, let them through - if ((Setting::getSettings()->two_factor_enabled=='1') && (Auth::user()->two_factor_optin!='1')) { + if (($settings->two_factor_enabled == '1') && (Auth::user()->two_factor_optin != '1')) { return $next($request); } // Otherwise make sure they're enrolled and show them the 2FA code screen - if ((Auth::user()->two_factor_secret!='') && (Auth::user()->two_factor_enrolled=='1')) { + if ((Auth::user()->two_factor_secret != '') && (Auth::user()->two_factor_enrolled == '1')) { return redirect()->route('two-factor')->with('info', 'Please enter your two-factor authentication code.'); } return redirect()->route('two-factor-enroll')->with('success', 'Please enroll a device in two-factor authentication.'); } } - return $next($request); + return $next($request); } } diff --git a/app/Http/Middleware/CheckLocale.php b/app/Http/Middleware/CheckLocale.php index 2f925e3a0b..75cba13261 100644 --- a/app/Http/Middleware/CheckLocale.php +++ b/app/Http/Middleware/CheckLocale.php @@ -2,37 +2,32 @@ namespace App\Http\Middleware; -use Closure; -use Config; -use Route; -use Schema; use App\Models\Setting; +use Closure; class CheckLocale { - /** - * Handle the locale for the user, default to settings otherwise - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @param string|null $guard - * @return mixed - */ - + /** + * Handle the locale for the user, default to settings otherwise. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $guard + * + * @return mixed + */ public function handle($request, Closure $next, $guard = null) { - - - if (Setting::getSettings()) { + if ($settings = Setting::getSettings()) { // User's preference if (($request->user()) && ($request->user()->locale)) { \App::setLocale($request->user()->locale); - // App setting preference - } elseif ((Setting::getSettings()) && (Setting::getSettings()->locale!='')) { - \App::setLocale(Setting::getSettings()->locale); + // App setting preference + } elseif ($settings->locale != '') { + \App::setLocale($settings->locale); - // Default app setting + // Default app setting } else { \App::setLocale(config('app.locale')); } diff --git a/app/Http/Middleware/CheckPermissions.php b/app/Http/Middleware/CheckPermissions.php index 41786776c5..a0b5be6ad6 100644 --- a/app/Http/Middleware/CheckPermissions.php +++ b/app/Http/Middleware/CheckPermissions.php @@ -3,8 +3,6 @@ namespace App\Http\Middleware; use Closure; -use Config; -use Route; use Gate; class CheckPermissions diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php index 515faca02b..7817127da3 100644 --- a/app/Http/Middleware/EncryptCookies.php +++ b/app/Http/Middleware/EncryptCookies.php @@ -7,7 +7,6 @@ use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter; class EncryptCookies extends BaseEncrypter { - /** * The names of the cookies that should not be encrypted. * diff --git a/app/Http/Requests/AssetCheckinRequest.php b/app/Http/Requests/AssetCheckinRequest.php index b9b87f1309..116b8b39f2 100644 --- a/app/Http/Requests/AssetCheckinRequest.php +++ b/app/Http/Requests/AssetCheckinRequest.php @@ -2,8 +2,6 @@ namespace App\Http\Requests; -use App\Http\Requests\Request; - class AssetCheckinRequest extends Request { /** diff --git a/app/Http/Requests/AssetCheckoutRequest.php b/app/Http/Requests/AssetCheckoutRequest.php index 66b861525e..4ba8ce09b7 100644 --- a/app/Http/Requests/AssetCheckoutRequest.php +++ b/app/Http/Requests/AssetCheckoutRequest.php @@ -2,8 +2,6 @@ namespace App\Http\Requests; -use App\Http\Requests\Request; - class AssetCheckoutRequest extends Request { /** @@ -25,7 +23,7 @@ class AssetCheckoutRequest extends Request { $rules = [ "assigned_user" => 'required_without_all:assigned_asset,assigned_location', - "assigned_asset" => 'required_without_all:assigned_user,assigned_location|different:'.$this->id, + "assigned_asset" => 'required_without_all:assigned_user,assigned_location', "assigned_location" => 'required_without_all:assigned_user,assigned_asset', "checkout_to_type" => 'required|in:asset,location,user' ]; diff --git a/app/Http/Requests/AssetFileRequest.php b/app/Http/Requests/AssetFileRequest.php index 5d3c72f6cb..74dfde3ab4 100644 --- a/app/Http/Requests/AssetFileRequest.php +++ b/app/Http/Requests/AssetFileRequest.php @@ -2,7 +2,6 @@ namespace App\Http\Requests; -use App\Http\Requests\Request; class AssetFileRequest extends Request { @@ -25,12 +24,7 @@ class AssetFileRequest extends Request { $max_file_size = \App\Helpers\Helper::file_upload_max_size(); return [ - 'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,lic|max:'.$max_file_size, + 'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,lic,xml,rtf|max:'.$max_file_size, ]; } - - public function response(array $errors) - { - return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag); - } } diff --git a/app/Http/Requests/AssetRequest.php b/app/Http/Requests/AssetRequest.php deleted file mode 100644 index 72c3a89ccb..0000000000 --- a/app/Http/Requests/AssetRequest.php +++ /dev/null @@ -1,85 +0,0 @@ - 'max:255|nullable', - 'model_id' => 'required|integer|exists:models,id', - 'status_id' => 'required|integer|exists:status_labels,id', - 'company_id' => 'integer|nullable', - 'warranty_months' => 'numeric|nullable|digits_between:0,240', - 'physical' => 'integer|nullable', - 'checkout_date' => 'date', - 'checkin_date' => 'date', - 'supplier_id' => 'integer|nullable', - 'status' => 'integer|nullable', - 'purchase_cost' => 'numeric|nullable', - "assigned_user" => 'sometimes:required_without_all:assigned_asset,assigned_location', - "assigned_asset" => 'sometimes:required_without_all:assigned_user,assigned_location', - "assigned_location" => 'sometimes:required_without_all:assigned_user,assigned_asset', - ]; - - $settings = \App\Models\Setting::getSettings(); - - $rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required'; - - if ($this->request->get('model_id') != '') { - $model = AssetModel::find($this->request->get('model_id')); - - if (($model) && (isset($model->fieldset)) && ($model->fieldset)) { - $rules += $model->fieldset->validation_rules(); - } - } - - return $rules; - - } - - - /** - * Handle a failed validation attempt. - * - * public function json($data = [], $status = 200, array $headers = [], $options = 0) - * - * @param \Illuminate\Contracts\Validation\Validator $validator - * @return void - * - * @throws \Illuminate\Http\Exceptions\HttpResponseException - */ - protected function failedValidation(Validator $validator) - { - $this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', new \Illuminate\Support\MessageBag($validator->errors()->toArray()))); - \Input::flash(); - throw new HttpResponseException(response()->json([ - 'status' => 'error', - 'messages' => $validator->errors(), - 'payload' => null - ], 422)); - } -} diff --git a/app/Http/Requests/ImageUploadRequest.php b/app/Http/Requests/ImageUploadRequest.php index 98b9997e04..2b43f9194d 100644 --- a/app/Http/Requests/ImageUploadRequest.php +++ b/app/Http/Requests/ImageUploadRequest.php @@ -5,6 +5,7 @@ namespace App\Http\Requests; use App\Models\SnipeModel; use Intervention\Image\Facades\Image; use enshrined\svgSanitize\Sanitizer; +use Storage; class ImageUploadRequest extends Request { @@ -26,8 +27,8 @@ class ImageUploadRequest extends Request public function rules() { return [ - 'image' => 'mimes:png,gif,jpg,jpeg,svg', - 'avatar' => 'mimes:png,gif,jpg,jpeg,svg', + 'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml', + 'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml', ]; } @@ -42,31 +43,53 @@ class ImageUploadRequest extends Request * @param String $path location for uploaded images, defaults to uploads/plural of item type. * @return SnipeModel Target asset is being checked out to. */ - public function handleImages($item, $w = 600, $path = null) + public function handleImages($item, $w = 600, $form_fieldname = null, $path = null, $db_fieldname = 'image') { $type = strtolower(class_basename(get_class($item))); if (is_null($path)) { - $path = str_plural($type); + $path = str_plural($type); + + if ($type == 'assetmodel') { + $path = 'models'; + } + + if ($type == 'user') { + $path = 'avatars'; + } } + if (is_null($form_fieldname)) { + $form_fieldname = 'image'; + } + + // This is dumb, but we need it for overriding field names for exceptions like avatars and logo uploads + if (is_null($db_fieldname)) { + $use_db_field = $form_fieldname; + } else { + $use_db_field = $db_fieldname; + } + + + \Log::info('Image path is: '.$path); + \Log::debug('Type is: '.$type); + \Log::debug('Form fieldname is: '.$form_fieldname); + \Log::debug('DB fieldname is: '.$use_db_field); \Log::debug('Trying to upload to '. $path); - if ($this->hasFile('image')) { + \Log::debug($this->file()); + + if ($this->hasFile($form_fieldname)) { if (!config('app.lock_passwords')) { - - if (!is_dir($path)) { - \Log::debug($path.' does not exist'); - mkdir($path); - } - - $image = $this->file('image'); + $image = $this->file($form_fieldname); $ext = $image->getClientOriginalExtension(); - $file_name = $type.'-'.str_random(18).'.'.$ext; - \Log::debug('File name will be: '.$file_name); + $file_name = $type.'-'.$form_fieldname.'-'.str_random(10).'.'.$ext; + + \Log::info('File name will be: '.$file_name); + \Log::debug('File extension is: '. $ext); if ($image->getClientOriginalExtension()!=='svg') { \Log::debug('Not an SVG - resize'); @@ -74,7 +97,13 @@ class ImageUploadRequest extends Request $upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); - })->save($path.'/'.$file_name); + }); + + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode()); + + + // If the file is an SVG, we need to clean it and NOT encode it } else { \Log::debug('This is an SVG'); $sanitizer = new Sanitizer(); @@ -83,35 +112,50 @@ class ImageUploadRequest extends Request try { \Log::debug('Trying to upload to: '.$path.'/'.$file_name); - file_put_contents($path.'/'.$file_name, $cleanSVG); + Storage::disk('public')->put($path.'/'.$file_name, $cleanSVG); } catch (\Exception $e) { + \Log::debug('Upload no workie :( '); \Log::debug($e); } } - // Remove Current image if exists - if (($item->image) && (file_exists($path.'/'.$item->image))) { + // Remove Current image if exists + if (Storage::disk('public')->exists($path.'/'.$item->{$use_db_field})) { + + \Log::debug('A file already exists that we are replacing - we should delete the old one.'); try { - unlink($path.'/'.$item->image); + Storage::disk('public')->delete($path.'/'.$item->{$use_db_field}); + \Log::debug('Old file '.$path.'/'.$file_name.' has been deleted.'); } catch (\Exception $e) { - \Log::debug($e); + \Log::debug('Could not delete old file. '.$path.'/'.$file_name.' does not exist?'); + } } - $item->image = $file_name; + $item->{$use_db_field} = $file_name; + } - } elseif ($this->input('image_delete')=='1') { + // If the user isn't uploading anything new but wants to delete their old image, do so + } else { + \Log::debug('No file passed for '.$form_fieldname); + if ($this->input('image_delete')=='1') { - try { - unlink($path.'/'.$item->image); - } catch (\Exception $e) { - \Log::debug($e); + \Log::debug('Deleting image'); + try { + + Storage::disk('public')->delete($path . '/' . $item->{$use_db_field}); + $item->{$use_db_field} = null; + + } catch (\Exception $e) { + \Log::debug($e); + } } - $item->image = null; } + + return $item; } -} \ No newline at end of file +} diff --git a/app/Http/Requests/ItemImportRequest.php b/app/Http/Requests/ItemImportRequest.php index fdbb5e76f8..e48c82bd90 100644 --- a/app/Http/Requests/ItemImportRequest.php +++ b/app/Http/Requests/ItemImportRequest.php @@ -42,21 +42,18 @@ class ItemImportRequest extends FormRequest $import->field_map = request('column-mappings'); $import->save(); $fieldMappings=[]; - if ($import->field_map) { - // This checks to make sure the field header has been mapped. - // If it hasn't been, it will throw an array_flip error + if ($import->field_map) { foreach ($import->field_map as $field => $fieldValue) { $errorMessage = null; if(is_null($fieldValue)){ - $errorMessage = 'All import fields must be mapped.'; + $errorMessage = trans('validation.import_field_empty'); $this->errorCallback($import, $field, $errorMessage); - + return $this->errors; } } - // We submit as csv field: column, but the importer is happier if we flip it here. $fieldMappings = array_change_key_case(array_flip($import->field_map), CASE_LOWER); // dd($fieldMappings); diff --git a/app/Http/Requests/LicenseCheckoutRequest.php b/app/Http/Requests/LicenseCheckoutRequest.php new file mode 100644 index 0000000000..a40c91653e --- /dev/null +++ b/app/Http/Requests/LicenseCheckoutRequest.php @@ -0,0 +1,31 @@ + 'string|nullable', + 'asset_id' => 'required_without:assigned_to', + ]; + } +} diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php index 7ab4fc16b2..35bfcdee93 100644 --- a/app/Http/Requests/Request.php +++ b/app/Http/Requests/Request.php @@ -2,7 +2,6 @@ namespace App\Http\Requests; use App\Helpers\Helper; - use Illuminate\Foundation\Http\FormRequest; abstract class Request extends FormRequest diff --git a/app/Http/Requests/SaveUserRequest.php b/app/Http/Requests/SaveUserRequest.php index 0de6a3bc02..ed44fc0939 100644 --- a/app/Http/Requests/SaveUserRequest.php +++ b/app/Http/Requests/SaveUserRequest.php @@ -19,6 +19,12 @@ class SaveUserRequest extends FormRequest return true; } + public function response(array $errors) + { + return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag); + } + + /** * Get the validation rules that apply to the request. * @@ -27,7 +33,9 @@ class SaveUserRequest extends FormRequest public function rules() { - $rules = []; + $rules = [ + 'manager_id' => "nullable|exists:users,id|different:users.id" + ]; switch($this->method()) { diff --git a/app/Http/Requests/SettingsLdapRequest.php b/app/Http/Requests/SettingsLdapRequest.php index 443404ac15..33da10fd65 100644 --- a/app/Http/Requests/SettingsLdapRequest.php +++ b/app/Http/Requests/SettingsLdapRequest.php @@ -2,7 +2,6 @@ namespace App\Http\Requests; -use App\Http\Requests\Request; use Session; class SettingsLdapRequest extends Request @@ -34,6 +33,7 @@ class SettingsLdapRequest extends Request "ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable', "ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable', "ldap_version" => 'sometimes|required_if:ldap_enabled,1|nullable', + "ad_domain" => 'sometimes|required_if:is_ad,1|nullable', ]; return $rules; diff --git a/app/Http/Requests/SettingsSamlRequest.php b/app/Http/Requests/SettingsSamlRequest.php new file mode 100644 index 0000000000..f8629a2b4d --- /dev/null +++ b/app/Http/Requests/SettingsSamlRequest.php @@ -0,0 +1,113 @@ + + * + * @since 5.0.0 + */ +class SettingsSamlRequest extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + * + * @return bool + */ + public function authorize() + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + ]; + } + + public function withValidator($validator) + { + $validator->after(function ($validator) { + if ($this->input('saml_enabled') == '1') { + + $idpMetadata = $this->input('saml_idp_metadata'); + if (!empty($idpMetadata)) { + try { + if (filter_var($idpMetadata, FILTER_VALIDATE_URL)) { + $metadataInfo = OneLogin_Saml2_IdPMetadataParser::parseRemoteXML($idpMetadata); + } else { + $metadataInfo = OneLogin_Saml2_IdPMetadataParser::parseXML($idpMetadata); + } + } catch (\Exception $e) { + $validator->errors()->add('saml_idp_metadata', trans('validation.url', ['attribute' => 'Metadata'])); + } + } + } + + if ($this->input('saml_sp_regenerate_keypair') == '1' || !$this->has('saml_sp_x509cert')) { + $dn = [ + "countryName" => "US", + "stateOrProvinceName" => "N/A", + "localityName" => "N/A", + "organizationName" => "Snipe-IT", + "commonName" => "Snipe-IT", + ]; + + $pkey = openssl_pkey_new([ + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_RSA, + ]); + + $csr = openssl_csr_new($dn, $pkey, ['digest_alg' => 'sha256']); + + $x509 = openssl_csr_sign($csr, null, $pkey, 3650, ['digest_alg' => 'sha256']); + + openssl_x509_export($x509, $x509cert); + openssl_pkey_export($pkey, $privateKey); + + $errors = []; + while (($error = openssl_error_string() !== false)) { + $errors[] = $error; + } + + if (!(empty($x509cert) && empty($privateKey))) { + $this->merge([ + 'saml_sp_x509cert' => $x509cert, + 'saml_sp_privatekey' => $privateKey, + ]); + } + } + + if (!empty($this->input('saml_custom_settings'))) { + $req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings')); + $custom_settings = []; + + foreach ($req_custom_settings as $custom_setting) { + $split = explode('=', $custom_setting, 2); + + if (count($split) == 2) { + $split[0] = trim($split[0]); + $split[1] = trim($split[1]); + + if (!empty($split[0])) { + $custom_settings[] = implode('=', $split); + } + } + } + + $this->merge(['saml_custom_settings' => implode(PHP_EOL, $custom_settings) . PHP_EOL]); + } + }); + } +} diff --git a/app/Http/Requests/SetupUserRequest.php b/app/Http/Requests/SetupUserRequest.php index a58595f757..2906d7d945 100644 --- a/app/Http/Requests/SetupUserRequest.php +++ b/app/Http/Requests/SetupUserRequest.php @@ -2,8 +2,6 @@ namespace App\Http\Requests; -use App\Http\Requests\Request; - class SetupUserRequest extends Request { /** diff --git a/app/Http/Traits/UniqueSerialTrait.php b/app/Http/Traits/UniqueSerialTrait.php index be9a885c08..b5529d7cf8 100644 --- a/app/Http/Traits/UniqueSerialTrait.php +++ b/app/Http/Traits/UniqueSerialTrait.php @@ -1,21 +1,24 @@ unique_serial=='1') { - return 'unique_undeleted:'.$this->table.','. $this->getKey(); + if ($settings = Setting::getSettings()) { + if ($settings->unique_serial == '1') { + return 'unique_undeleted:'.$this->table.','.$this->getKey(); } } } diff --git a/app/Http/Transformers/AccessoriesTransformer.php b/app/Http/Transformers/AccessoriesTransformer.php index fd6832e00c..8b56ae05f6 100644 --- a/app/Http/Transformers/AccessoriesTransformer.php +++ b/app/Http/Transformers/AccessoriesTransformer.php @@ -1,10 +1,11 @@ $accessory->id, 'name' => e($accessory->name), + 'image' => ($accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory->image)) : null, 'company' => ($accessory->company) ? ['id' => $accessory->company->id,'name'=> e($accessory->company->name)] : null, 'manufacturer' => ($accessory->manufacturer) ? ['id' => $accessory->manufacturer->id,'name'=> e($accessory->manufacturer->name)] : null, 'supplier' => ($accessory->supplier) ? ['id' => $accessory->supplier->id,'name'=> e($accessory->supplier->name)] : null, @@ -36,17 +38,17 @@ class AccessoriesTransformer 'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null, 'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, 'remaining_qty' => $accessory->numRemaining(), - 'image' => ($accessory->image) ? url('/').'/uploads/accessories/'.e($accessory->image) : null, + 'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'), ]; $permissions_array['available_actions'] = [ - 'checkout' => Gate::allows('checkout', Accessory::class) ? true : false, + 'checkout' => Gate::allows('checkout', Accessory::class), 'checkin' => false, - 'update' => Gate::allows('update', Accessory::class) ? true : false, - 'delete' => Gate::allows('delete', Accessory::class) ? true : false, + 'update' => Gate::allows('update', Accessory::class) , + 'delete' => Gate::allows('delete', Accessory::class), ]; $permissions_array['user_can_checkout'] = false; @@ -61,7 +63,7 @@ class AccessoriesTransformer } - public function transformCheckedoutAccessory ($accessory_users, $total) + public function transformCheckedoutAccessory ($accessory, $accessory_users, $total) { @@ -75,6 +77,7 @@ class AccessoriesTransformer 'first_name'=> e($user->first_name), 'last_name'=> e($user->last_name), 'employee_number' => e($user->employee_num), + 'checkout_notes' => $accessory->lastCheckoutArray[0]['note'], 'type' => 'user', 'available_actions' => ['checkin' => true] ]; diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 7d982f1ad8..8e1942a518 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -1,11 +1,10 @@ (int) $actionlog->id, 'icon' => $icon, 'file' => ($actionlog->filename!='') ? @@ -114,9 +113,9 @@ class ActionlogsTransformer ] : null, 'note' => ($actionlog->note) ? e($actionlog->note): null, - 'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null, + 'signature_file' => ($actionlog->signature_filename) ? route('log.signature.view', ['filename' => $actionlog->signature_filename ]) : null, 'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null, - + 'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): null, ]; diff --git a/app/Http/Transformers/AssetMaintenancesTransformer.php b/app/Http/Transformers/AssetMaintenancesTransformer.php index cc25d95093..49c1b38b65 100644 --- a/app/Http/Transformers/AssetMaintenancesTransformer.php +++ b/app/Http/Transformers/AssetMaintenancesTransformer.php @@ -1,10 +1,10 @@ e($assetmaintenance->asset->asset_tag) ] : null, + 'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [ + 'id' => (int) $assetmaintenance->asset->model->id, + 'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null + ] : null, 'company' => (($assetmaintenance->asset) && ($assetmaintenance->asset->company)) ? [ 'id' => (int) $assetmaintenance->asset->company->id, 'name'=> ($assetmaintenance->asset->company->name) ? e($assetmaintenance->asset->company->name) : null, @@ -54,8 +58,8 @@ class AssetMaintenancesTransformer ]; $permissions_array['available_actions'] = [ - 'update' => (bool) Gate::allows('update', Asset::class), - 'delete' => (bool) Gate::allows('delete', Asset::class), + 'update' => Gate::allows('update', Asset::class), + 'delete' => Gate::allows('delete', Asset::class), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/AssetModelsTransformer.php b/app/Http/Transformers/AssetModelsTransformer.php index 2bb0a9e1a9..3f561b7b9f 100644 --- a/app/Http/Transformers/AssetModelsTransformer.php +++ b/app/Http/Transformers/AssetModelsTransformer.php @@ -1,10 +1,11 @@ (int) $assetmodel->manufacturer->id, 'name'=> e($assetmodel->manufacturer->name) ] : null, - 'image' => ($assetmodel->image!='') ? app('models_upload_url').e($assetmodel->image) : null, + 'image' => ($assetmodel->image!='') ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null, 'model_number' => e($assetmodel->model_number), 'depreciation' => ($assetmodel->depreciation) ? [ 'id' => (int) $assetmodel->depreciation->id, @@ -44,6 +45,7 @@ class AssetModelsTransformer 'name'=> e($assetmodel->fieldset->name) ] : null, 'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol .' months': 'None', + 'requestable' => ($assetmodel->requestable =='1') ? true : false, 'notes' => e($assetmodel->notes), 'created_at' => Helper::getFormattedDateObject($assetmodel->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($assetmodel->updated_at, 'datetime'), @@ -52,10 +54,10 @@ class AssetModelsTransformer ]; $permissions_array['available_actions'] = [ - 'update' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at=='')) ? true : false, - 'delete' => (Gate::allows('delete', AssetModel::class) && ($assetmodel->assets_count==0) && ($assetmodel->deleted_at=='')) ? true : false, - 'clone' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at=='')) , - 'restore' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at!='')) ? true : false, + 'update' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at=='')), + 'delete' => (Gate::allows('delete', AssetModel::class) && ($assetmodel->assets_count==0)), + 'clone' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at=='')), + 'restore' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at!='')), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index 84b5af4193..400a5dd111 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -1,11 +1,10 @@ (bool) Gate::allows('checkout', Asset::class), - 'checkin' => (bool) Gate::allows('checkin', Asset::class), - 'clone' => Gate::allows('create', Asset::class) ? true : false, + 'checkout' => Gate::allows('checkout', Asset::class), + 'checkin' => Gate::allows('checkin', Asset::class), + 'clone' => Gate::allows('create', Asset::class), 'restore' => false, 'update' => (bool) Gate::allows('update', Asset::class), - 'delete' => (bool) Gate::allows('delete', Asset::class), + 'delete' => ($asset->assigned_to=='' && Gate::allows('delete', Asset::class)), ]; if ($asset->deleted_at!='') { $permissions_array['available_actions'] = [ 'checkout' => true, 'checkin' => false, - 'clone' => Gate::allows('create', Asset::class) ? true : false, - 'restore' => Gate::allows('create', Asset::class) ? true : false, + 'clone' => Gate::allows('create', Asset::class), + 'restore' => Gate::allows('create', Asset::class), 'update' => false, 'delete' => false, ]; diff --git a/app/Http/Transformers/CategoriesTransformer.php b/app/Http/Transformers/CategoriesTransformer.php index 710bf84bc5..a07d8b345c 100644 --- a/app/Http/Transformers/CategoriesTransformer.php +++ b/app/Http/Transformers/CategoriesTransformer.php @@ -1,10 +1,11 @@ (int) $category->id, 'name' => e($category->name), - 'image' => ($category->image) ? app('categories_upload_url').e($category->image) : null, - 'category_type' => e($category->category_type), - 'eula' => ($category->getEula()) ? true : false, - 'checkin_email' => ($category->checkin_email =='1') ? true : false, - 'require_acceptance' => ($category->require_acceptance =='1') ? true : false, + 'image' => ($category->image) ? Storage::disk('public')->url('categories/'.e($category->image)) : null, + 'category_type' => ucwords(e($category->category_type)), + 'has_eula' => ($category->getEula() ? true : false), + 'eula' => ($category->getEula()), + 'checkin_email' => ($category->checkin_email =='1'), + 'require_acceptance' => ($category->require_acceptance == '1'), + 'item_count' => (int) $category->itemCount(), 'assets_count' => (int) $category->assets_count, 'accessories_count' => (int) $category->accessories_count, 'consumables_count' => (int) $category->consumables_count, @@ -40,8 +43,8 @@ class CategoriesTransformer ]; $permissions_array['available_actions'] = [ - 'update' => Gate::allows('update', Category::class) ? true : false, - 'delete' => (Gate::allows('delete', Category::class) && ($category->assets_count == 0) && ($category->accessories_count == 0) && ($category->consumables_count == 0) && ($category->components_count == 0) && ($category->licenses_count == 0)) ? true : false, + 'update' => Gate::allows('update', Category::class), + 'delete' => $category->isDeletable(), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/CompaniesTransformer.php b/app/Http/Transformers/CompaniesTransformer.php index 96951bdf85..4460b30c14 100644 --- a/app/Http/Transformers/CompaniesTransformer.php +++ b/app/Http/Transformers/CompaniesTransformer.php @@ -1,10 +1,11 @@ (int) $company->id, 'name' => e($company->name), - 'image' => ($company->image) ? app('companies_upload_url').e($company->image) : null, + 'image' => ($company->image) ? Storage::disk('public')->url('companies/'.e($company->image)) : null, "created_at" => Helper::getFormattedDateObject($company->created_at, 'datetime'), "updated_at" => Helper::getFormattedDateObject($company->updated_at, 'datetime'), "assets_count" => (int) $company->assets_count, @@ -37,8 +38,8 @@ class CompaniesTransformer ]; $permissions_array['available_actions'] = [ - 'update' => Gate::allows('update', Company::class) ? true : false, - 'delete' => (Gate::allows('delete', Company::class) && ($company->assets_count == 0) && ($company->accessories_count == 0) && ($company->consumables_count == 0) && ($company->components_count == 0) && ($company->users_count == 0)) ? true : false, + 'update' => Gate::allows('update', Company::class), + 'delete' => $company->isDeletable() ]; $array += $permissions_array; diff --git a/app/Http/Transformers/ComponentsAssetsTransformer.php b/app/Http/Transformers/ComponentsAssetsTransformer.php index f8a169ca32..8ce3a8600d 100644 --- a/app/Http/Transformers/ComponentsAssetsTransformer.php +++ b/app/Http/Transformers/ComponentsAssetsTransformer.php @@ -2,10 +2,8 @@ namespace App\Http\Transformers; use App\Models\Asset; -use Illuminate\Database\Eloquent\Collection; -use App\Http\Transformers\UsersTransformer; use Gate; - +use Illuminate\Database\Eloquent\Collection; class ComponentsAssetsTransformer { @@ -30,10 +28,10 @@ class ComponentsAssetsTransformer ]; $permissions_array['available_actions'] = [ - 'checkout' => Gate::allows('checkout', Asset::class) ? true : false, - 'checkin' => Gate::allows('checkin', Asset::class) ? true : false, - 'update' => Gate::allows('update', Asset::class) ? true : false, - 'delete' => Gate::allows('delete', Asset::class) ? true : false, + 'checkout' => Gate::allows('checkout', Asset::class), + 'checkin' => Gate::allows('checkin', Asset::class), + 'update' => Gate::allows('update', Asset::class), + 'delete' => Gate::allows('delete', Asset::class), ]; diff --git a/app/Http/Transformers/ComponentsTransformer.php b/app/Http/Transformers/ComponentsTransformer.php index cf51b55d79..c27deb2a1f 100644 --- a/app/Http/Transformers/ComponentsTransformer.php +++ b/app/Http/Transformers/ComponentsTransformer.php @@ -1,10 +1,11 @@ (int) $component->id, 'name' => e($component->name), - 'image' => ($component->image) ? e(url('/').'/uploads/components/'.e($component->image)) : null, + 'image' => ($component->image) ? Storage::disk('public')->url('components/'.e($component->image)) : null, 'serial' => ($component->serial) ? e($component->serial) : null, 'location' => ($component->location) ? [ 'id' => (int) $component->location->id, @@ -34,10 +35,6 @@ class ComponentsTransformer 'id' => (int) $component->category->id, 'name' => e($component->category->name) ] : null, - 'location' => ($component->location) ? [ - 'id' => (int) $component->location->id, - 'name' => e($component->location->name) - ] : null, 'order_number' => e($component->order_number), 'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'), 'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost), @@ -52,10 +49,10 @@ class ComponentsTransformer ]; $permissions_array['available_actions'] = [ - 'checkout' => (bool) Gate::allows('checkout', Component::class), - 'checkin' => (bool) Gate::allows('checkin', Component::class), - 'update' => (bool) Gate::allows('update', Component::class), - 'delete' => (bool) Gate::allows('delete', Component::class), + 'checkout' => Gate::allows('checkout', Component::class), + 'checkin' => Gate::allows('checkin', Component::class), + 'update' => Gate::allows('update', Component::class), + 'delete' => Gate::allows('delete', Component::class), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/ConsumablesTransformer.php b/app/Http/Transformers/ConsumablesTransformer.php index 3d68697a58..c82299de98 100644 --- a/app/Http/Transformers/ConsumablesTransformer.php +++ b/app/Http/Transformers/ConsumablesTransformer.php @@ -1,10 +1,11 @@ (int) $consumable->id, 'name' => e($consumable->name), - 'image' => ($consumable->image) ? e(url('/').'/uploads/consumables/'.e($consumable->image)) : null, + 'image' => ($consumable->image) ? Storage::disk('public')->url('consumables/'.e($consumable->image)) : null, 'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null, 'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null, 'item_no' => e($consumable->item_no), @@ -47,10 +48,10 @@ class ConsumablesTransformer } $permissions_array['available_actions'] = [ - 'checkout' => Gate::allows('checkout', Consumable::class) ? true : false, - 'checkin' => Gate::allows('checkin', Consumable::class) ? true : false, - 'update' => Gate::allows('update', Consumable::class) ? true : false, - 'delete' => Gate::allows('delete', Consumable::class) ? true : false, + 'checkout' => Gate::allows('checkout', Consumable::class), + 'checkin' => Gate::allows('checkin', Consumable::class), + 'update' => Gate::allows('update', Consumable::class), + 'delete' => Gate::allows('delete', Consumable::class), ]; $array += $permissions_array; return $array; diff --git a/app/Http/Transformers/CustomFieldsTransformer.php b/app/Http/Transformers/CustomFieldsTransformer.php index 1f8f02e278..1ef6904de8 100644 --- a/app/Http/Transformers/CustomFieldsTransformer.php +++ b/app/Http/Transformers/CustomFieldsTransformer.php @@ -1,10 +1,9 @@ (int) $department->id, 'name' => e($department->name), - 'image' => ($department->image) ? app('departments_upload_url').e($department->image) : null, + 'image' => ($department->image) ? Storage::disk('public')->url(app('departments_upload_url').e($department->image)) : null, 'company' => ($department->company) ? [ 'id' => (int) $department->company->id, 'name'=> e($department->company->name) @@ -46,8 +47,8 @@ class DepartmentsTransformer ]; $permissions_array['available_actions'] = [ - 'update' => Gate::allows('update', Department::class) ? true : false, - 'delete' => (Gate::allows('delete', Department::class) && ($department->users_count==0) && ($department->deleted_at=='')) ? true : false, + 'update' => Gate::allows('update', Department::class), + 'delete' => (Gate::allows('delete', Department::class) && ($department->users_count==0)), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/DepreciationsTransformer.php b/app/Http/Transformers/DepreciationsTransformer.php index 70304005c9..0b9d011e23 100644 --- a/app/Http/Transformers/DepreciationsTransformer.php +++ b/app/Http/Transformers/DepreciationsTransformer.php @@ -1,10 +1,10 @@ Gate::allows('update', Depreciation::class) ? true : false, - 'delete' => Gate::allows('delete', Depreciation::class) ? true : false, + 'update' => Gate::allows('update', Depreciation::class), + 'delete' => Gate::allows('delete', Depreciation::class), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/GroupsTransformer.php b/app/Http/Transformers/GroupsTransformer.php index 3cec01f99f..8f116aad76 100644 --- a/app/Http/Transformers/GroupsTransformer.php +++ b/app/Http/Transformers/GroupsTransformer.php @@ -1,10 +1,10 @@ e($seat->location()->name) ] : null, 'reassignable' => (bool) $seat->license->reassignable, - 'user_can_checkout' => (($seat->assigned_to=='') && ($seat->asset_id=='')) ? true : false, + 'user_can_checkout' => (($seat->assigned_to=='') && ($seat->asset_id=='')), ]; $permissions_array['available_actions'] = [ - 'checkout' => Gate::allows('checkout', License::class) ? true : false, - 'checkin' => Gate::allows('checkin', License::class) ? true : false, - 'clone' => Gate::allows('create', License::class) ? true : false, - 'update' => Gate::allows('update', License::class) ? true : false, - 'delete' => Gate::allows('delete', License::class) ? true : false, + 'checkout' => Gate::allows('checkout', License::class), + 'checkin' => Gate::allows('checkin', License::class), + 'clone' => Gate::allows('create', License::class), + 'update' => Gate::allows('update', License::class), + 'delete' => Gate::allows('delete', License::class), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/LicensesTransformer.php b/app/Http/Transformers/LicensesTransformer.php index fa7630e8de..dfce3d42b4 100644 --- a/app/Http/Transformers/LicensesTransformer.php +++ b/app/Http/Transformers/LicensesTransformer.php @@ -1,10 +1,10 @@ (int) $license->free_seats_count, 'license_name' => e($license->license_name), 'license_email' => e($license->license_email), + 'reassignable' => ($license->reassignable == 1) ? true : false, 'maintained' => ($license->maintained == 1) ? true : false, 'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id,'name'=> e($license->supplier->name)] : null, 'category' => ($license->category) ? ['id' => (int) $license->category->id,'name'=> e($license->category->name)] : null, @@ -45,11 +46,11 @@ class LicensesTransformer ]; $permissions_array['available_actions'] = [ - 'checkout' => Gate::allows('checkout', License::class) ? true : false, - 'checkin' => Gate::allows('checkin', License::class) ? true : false, - 'clone' => Gate::allows('create', License::class) ? true : false, - 'update' => Gate::allows('update', License::class) ? true : false, - 'delete' => Gate::allows('delete', License::class) ? true : false, + 'checkout' => Gate::allows('checkout', License::class), + 'checkin' => Gate::allows('checkin', License::class), + 'clone' => Gate::allows('create', License::class), + 'update' => Gate::allows('update', License::class), + 'delete' => Gate::allows('delete', License::class), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/LocationsTransformer.php b/app/Http/Transformers/LocationsTransformer.php index b418ebb5f8..92f5cc965d 100644 --- a/app/Http/Transformers/LocationsTransformer.php +++ b/app/Http/Transformers/LocationsTransformer.php @@ -1,10 +1,11 @@ children as $child) { - $children_arr[] = [ - 'id' => (int) $child->id, - 'name' => $child->name - ]; + if(!is_null($location->children)){ + foreach($location->children as $child) { + $children_arr[] = [ + 'id' => (int) $child->id, + 'name' => $child->name + ]; + } } $array = [ 'id' => (int) $location->id, 'name' => e($location->name), - 'image' => ($location->image) ? app('locations_upload_url').e($location->image) : null, + 'image' => ($location->image) ? Storage::disk('public')->url('locations/'.e($location->image)) : null, 'address' => ($location->address) ? e($location->address) : null, 'address2' => ($location->address2) ? e($location->address2) : null, 'city' => ($location->city) ? e($location->city) : null, @@ -58,7 +61,7 @@ class LocationsTransformer $permissions_array['available_actions'] = [ 'update' => Gate::allows('update', Location::class) ? true : false, - 'delete' => (Gate::allows('delete', Location::class) && ($location->assigned_assets_count==0) && ($location->assets_count==0) && ($location->users_count==0) && ($location->deleted_at=='')) ? true : false, + 'delete' => $location->isDeletable(), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/LoginAttemptsTransformer.php b/app/Http/Transformers/LoginAttemptsTransformer.php new file mode 100644 index 0000000000..a0af36d121 --- /dev/null +++ b/app/Http/Transformers/LoginAttemptsTransformer.php @@ -0,0 +1,40 @@ +transformDatatables($array, $total); + } + + public function transformLoginAttempt($login_attempt) + { + + if ($login_attempt) { + $array = [ + 'id' => (int) $login_attempt->id, + 'username' => e($login_attempt->username), + 'user_agent' => e($login_attempt->user_agent), + 'remote_ip' => (!config('app.lock_passwords')) ? e($login_attempt->remote_ip) : '--', + 'successful' => e($login_attempt->successful), + 'created_at' => Helper::getFormattedDateObject($login_attempt->created_at, 'datetime'), + ]; + return $array; + } + + + } + + + +} diff --git a/app/Http/Transformers/ManufacturersTransformer.php b/app/Http/Transformers/ManufacturersTransformer.php index 3db65ee9f0..1cdf5dd3fe 100644 --- a/app/Http/Transformers/ManufacturersTransformer.php +++ b/app/Http/Transformers/ManufacturersTransformer.php @@ -1,10 +1,11 @@ (int) $manufacturer->id, 'name' => e($manufacturer->name), 'url' => e($manufacturer->url), - 'image' => ($manufacturer->image) ? app('manufacturers_upload_url').e($manufacturer->image) : null, + 'image' => ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.e($manufacturer->image)) : null, 'support_url' => e($manufacturer->support_url), 'support_phone' => e($manufacturer->support_phone), 'support_email' => e($manufacturer->support_email), @@ -40,9 +41,9 @@ class ManufacturersTransformer ]; $permissions_array['available_actions'] = [ - 'update' => (($manufacturer->deleted_at=='') && (Gate::allows('update', Manufacturer::class))) ? true : false, - 'restore' => (($manufacturer->deleted_at!='') && (Gate::allows('create', Manufacturer::class))) ? true : false, - 'delete' => (Gate::allows('delete', Manufacturer::class) && ($manufacturer->assets_count == 0) && ($manufacturer->licenses_count==0) && ($manufacturer->consumables_count==0) && ($manufacturer->accessories_count==0) && ($manufacturer->deleted_at=='')) ? true : false, + 'update' => (($manufacturer->deleted_at=='') && (Gate::allows('update', Manufacturer::class))), + 'restore' => (($manufacturer->deleted_at!='') && (Gate::allows('create', Manufacturer::class))), + 'delete' => $manufacturer->isDeletable(), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/PredefinedKitsTransformer.php b/app/Http/Transformers/PredefinedKitsTransformer.php new file mode 100644 index 0000000000..57e3aa62f4 --- /dev/null +++ b/app/Http/Transformers/PredefinedKitsTransformer.php @@ -0,0 +1,81 @@ +] + * @return array + */ +class PredefinedKitsTransformer +{ + + public function transformPredefinedKits (Collection $kits, $total) + { + $array = array(); + foreach ($kits as $kit) { + $array[] = self::transformPredefinedKit($kit); + } + return (new DatatablesTransformer)->transformDatatables($array, $total); + } + + public function transformPredefinedKit (PredefinedKit $kit) + { + $array = [ + 'id' => (int) $kit->id, + 'name' => e($kit->name) + ]; + + $permissions_array['available_actions'] = [ + 'update' => Gate::allows('update', PredefinedKit::class), + 'delete' => Gate::allows('delete', PredefinedKit::class), + 'checkout' => Gate::allows('checkout', PredefinedKit::class), + // 'clone' => Gate::allows('create', PredefinedKit::class), + // 'restore' => Gate::allows('create', PredefinedKit::class), + ]; + $array['user_can_checkout'] = true; + $array += $permissions_array; + return $array; + } + + /** + * transform collection of any elemets attached to kit + * @return array + */ + public function transformElements(Collection $elements, $total) { + $array = array(); + foreach ($elements as $element) { + $array[] = self::transformElement($element); + } + return (new DatatablesTransformer)->transformDatatables($array, $total); + } + + public function transformElement(SnipeModel $element) { + $array = [ + 'id' => (int) $element->id, + 'pivot_id' => (int) $element->pivot->id, + 'owner_id' => (int) $element->pivot->kit_id, + 'quantity' => (int) $element->pivot->quantity, + 'name' => e($element->name) + ]; + + $permissions_array['available_actions'] = [ + 'update' => Gate::allows('update', PredefinedKit::class), + 'delete' => Gate::allows('delete', PredefinedKit::class), + ]; + + $array += $permissions_array; + return $array; + } + + public function transformPredefinedKitsDatatable($kits) { + return (new DatatablesTransformer)->transformDatatables($kits); + } + + +} diff --git a/app/Http/Transformers/StatuslabelsTransformer.php b/app/Http/Transformers/StatuslabelsTransformer.php index f76557a0bf..b320129f37 100644 --- a/app/Http/Transformers/StatuslabelsTransformer.php +++ b/app/Http/Transformers/StatuslabelsTransformer.php @@ -1,10 +1,10 @@ (int) $supplier->id, 'name' => e($supplier->name), - 'image' => ($supplier->image) ? app('suppliers_upload_url').e($supplier->image) : null, - 'address' => ($supplier->address) ? e($supplier->address) : null, - 'address2' => ($supplier->address2) ? e($supplier->address2) : null, - 'city' => ($supplier->city) ? e($supplier->city) : null, - 'state' => ($supplier->state) ? e($supplier->state) : null, - 'country' => ($supplier->country) ? e($supplier->country) : null, - 'zip' => ($supplier->zip) ? e($supplier->zip) : null, - 'fax' => ($supplier->fax) ? e($supplier->fax) : null, - 'phone' => ($supplier->phone) ? e($supplier->phone) : null, - 'email' => ($supplier->email) ? e($supplier->email) : null, - 'contact' => ($supplier->contact) ? e($supplier->contact) : null, + 'image' => ($supplier->image) ? Storage::disk('public')->url('suppliers/'.e($supplier->image)) : null, + 'url' => e($supplier->url), + 'address' => e($supplier->address), + 'address2' => e($supplier->address2), + 'city' => e($supplier->city), + 'state' => e($supplier->state), + 'country' => e($supplier->country), + 'zip' => e($supplier->zip), + 'fax' => e($supplier->fax), + 'phone' => e($supplier->phone), + 'email' => e($supplier->email), + 'contact' => e($supplier->contact), 'assets_count' => (int) $supplier->assets_count, 'accessories_count' => (int) $supplier->accessories_count, 'licenses_count' => (int) $supplier->licenses_count, @@ -46,8 +48,8 @@ class SuppliersTransformer ]; $permissions_array['available_actions'] = [ - 'update' => Gate::allows('update', Supplier::class) ? true : false, - 'delete' => (Gate::allows('delete', Supplier::class) && ($supplier->assets_count == 0) && ($supplier->licenses_count == 0) && ($supplier->accessories_count == 0)) ? true : false, + 'update' => Gate::allows('update', Supplier::class), + 'delete' => (Gate::allows('delete', Supplier::class) && ($supplier->assets_count == 0) && ($supplier->licenses_count == 0) && ($supplier->accessories_count == 0)), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index 1910de0a7d..5f844d5883 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -1,11 +1,10 @@ (Gate::allows('update', User::class) && ($user->deleted_at=='')) ? true : false, - 'delete' => (Gate::allows('delete', User::class) && ($user->deleted_at=='') && ($user->assets_count == 0) && ($user->licenses_count == 0) && ($user->accessories_count == 0) && ($user->consumables_count == 0)) ? true : false, + 'update' => (Gate::allows('update', User::class) && ($user->deleted_at=='')), + 'delete' => (Gate::allows('delete', User::class) && ($user->assets_count == 0) && ($user->licenses_count == 0) && ($user->accessories_count == 0) && ($user->consumables_count == 0)), 'clone' => (Gate::allows('create', User::class) && ($user->deleted_at=='')) , - 'restore' => (Gate::allows('create', User::class) && ($user->deleted_at!='')) ? true : false, + 'restore' => (Gate::allows('create', User::class) && ($user->deleted_at!='')), ]; $array += $permissions_array; @@ -100,8 +99,4 @@ class UsersTransformer return (new DatatablesTransformer)->transformDatatables($users); } - - - - } diff --git a/app/Importer/AccessoryImporter.php b/app/Importer/AccessoryImporter.php index eaf24783eb..709b58ea3c 100644 --- a/app/Importer/AccessoryImporter.php +++ b/app/Importer/AccessoryImporter.php @@ -2,7 +2,6 @@ namespace App\Importer; -use App\Helpers\Helper; use App\Models\Accessory; class AccessoryImporter extends ItemImporter diff --git a/app/Importer/AssetImporter.php b/app/Importer/AssetImporter.php index bbf896e258..bdc254cb06 100644 --- a/app/Importer/AssetImporter.php +++ b/app/Importer/AssetImporter.php @@ -2,10 +2,7 @@ namespace App\Importer; -use App\Helpers\Helper; use App\Models\Asset; -use App\Models\Category; -use App\Models\Manufacturer; use App\Models\Statuslabel; class AssetImporter extends ItemImporter diff --git a/app/Importer/ConsumableImporter.php b/app/Importer/ConsumableImporter.php index a25a8b56f7..e7972bb2cd 100644 --- a/app/Importer/ConsumableImporter.php +++ b/app/Importer/ConsumableImporter.php @@ -2,7 +2,6 @@ namespace App\Importer; -use App\Helpers\Helper; use App\Models\Consumable; class ConsumableImporter extends ItemImporter diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index dfd20bd2f6..6466c3b2d1 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -2,12 +2,12 @@ namespace App\Importer; use App\Models\CustomField; +use App\Models\Department; use App\Models\Setting; use App\Models\User; -use App\Models\Department; +use Illuminate\Support\Facades\Auth; use ForceUTF8\Encoding; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use League\Csv\Reader; @@ -121,6 +121,13 @@ abstract class Importer // Cached Values for import lookups protected $customFields; + /** + * Sets up the database transaction and logging for the importer + * + * @return void + * @author Daniel Meltzer + * @since 5.0 + */ public function import() { $headerRow = $this->csv->fetchOne(); @@ -159,7 +166,7 @@ abstract class Importer // This 'inverts' the fields such that we have a collection of fields indexed by name. $this->customFields = CustomField::All()->reduce(function ($nameLookup, $field) { $nameLookup[$field['name']] = $field; - return $nameLookup; + return $nameLookup; }); // Remove any custom fields that do not exist in the header row. This prevents nulling out values that shouldn't exist. // In detail, we compare the lower case name of custom fields (indexed by name) to the keys in the header row. This @@ -277,7 +284,12 @@ abstract class Importer 'username' => $this->findCsvMatch($row, "username"), 'activated' => $this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')), ]; - \Log::debug('Importer.php Activated: '.$this->findCsvMatch($row, 'activated')); + + // Maybe we're lucky and the user already exists. + if($user = User::where('username', $user_array['username'])->first()) { + $this->log('User '.$user_array['username'].' already exists'); + return $user; + } // If the full name is empty, bail out--we need this to extract first name (at the very least) if(empty($user_array['full_name'])) { @@ -296,7 +308,7 @@ abstract class Importer $user_array['email'] = User::generateEmailFromFullName($user_array['full_name']); } - $user_formatted_array = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $user_array['full_name']); + $user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format); $user_array['first_name'] = $user_formatted_array['first_name']; $user_array['last_name'] = $user_formatted_array['last_name']; @@ -321,19 +333,18 @@ abstract class Importer // No Luck, let's create one. $user = new User; - $user->first_name = $user_array['first_name']; - $user->last_name = $user_array['last_name']; - $user->username = $user_array['username']; - $user->email = $user_array['email']; - $user->manager_id = (isset($user_array['manager_id']) ? $user_array['manager_id'] : null); - $user->department_id = (isset($user_array['department_id']) ? $user_array['department_id']: null); - $user->activated = $user_array['activated']; - $user->password = $this->tempPassword; + $user->first_name = $user_array['first_name']; + $user->last_name = $user_array['last_name']; + $user->username = $user_array['username']; + $user->email = $user_array['email']; + $user->manager_id = $user_array['manager_id'] ?? null; + $user->department_id = $user_array['department_id'] ?? null; + $user->activated = 1; + $user->password = $this->tempPassword; \Log::debug('Creating a user with the following attributes: '.print_r($user_array, true)); if ($user->save()) { - \Log::debug('Importer.php Name: '.$user->first_name.' '.$user->last_name.' ('.$user->username.')'); $this->log('User '.$user_array['username'].' created'); return $user; } @@ -384,9 +395,9 @@ abstract class Importer } /** - * Sets the Are we updating items in the import. + * Sets whether or not we should notify the user with a welcome email * - * @param bool $updating the updating + * @param bool $send_welcome the send-welcome flag * * @return self */ diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index 224a612e7b..b68d9d5e8c 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -2,7 +2,6 @@ namespace App\Importer; -use App\Importer\UserImporter; use App\Models\AssetModel; use App\Models\Category; use App\Models\Company; @@ -10,7 +9,6 @@ use App\Models\Location; use App\Models\Manufacturer; use App\Models\Statuslabel; use App\Models\Supplier; -use App\Models\Department; use App\Models\User; class ItemImporter extends Importer @@ -61,8 +59,9 @@ class ItemImporter extends Importer $this->item['department_id'] = $this->createOrFetchDepartment($item_department); } - $item_manager_first_name = $this->findCsvMatch($row, "manager_first_name"); - $item_manager_last_name = $this->findCsvMatch($row, "manager_last_name"); + $item_manager_first_name = $this->findCsvMatch($row, "manage_first_name"); + $item_manager_last_name = $this->findCsvMatch($row, "manage_last_name"); + if ($this->shouldUpdateField($item_manager_first_name)) { $this->item['manager_id'] = $this->fetchManager($item_manager_first_name, $item_manager_last_name); } @@ -86,7 +85,6 @@ class ItemImporter extends Importer if(get_class($this) !== UserImporter::class) { // $this->item["user"] = $this->createOrFetchUser($row); $this->item["checkout_target"] = $this->determineCheckout($row); - } } @@ -160,7 +158,7 @@ class ItemImporter extends Importer * @param $field string * @return boolean */ - private function shouldUpdateField($field) + protected function shouldUpdateField($field) { if (empty($field)) { return false; @@ -173,8 +171,7 @@ class ItemImporter extends Importer * @author Daniel Melzter * @since 3.0 * @param array - * @param $category Category - * @param $row Manufacturer + * @param $row Row * @return int Id of asset model created/found * @internal param $asset_modelno string */ @@ -294,6 +291,27 @@ class ItemImporter extends Importer + /** + * Fetch an existing manager + * + * @author A. Gianotto + * @since 4.6.5 + * @param $user_manager string + * @return int id of company created/found + */ + public function fetchManager($user_manager_first_name, $user_manager_last_name) + { + $manager = User::where('first_name', '=', $user_manager_first_name) + ->where('last_name', '=', $user_manager_last_name)->first(); + if ($manager) { + $this->log('A matching Manager ' . $user_manager_first_name . ' '. $user_manager_last_name . ' already exists'); + return $manager->id; + } + $this->log('No matching Manager ' . $user_manager_first_name . ' '. $user_manager_last_name . ' found. If their user account is being created through this import, you should re-process this file again. '); + return null; + } + + /** * Fetch the existing status label or create new if it doesn't exist. * diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index 7be62b7b44..f9bc1d825b 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -2,11 +2,9 @@ namespace App\Importer; -use App\Helpers\Helper; use App\Models\Asset; -use App\Models\Category; use App\Models\License; -use App\Models\Manufacturer; +use Illuminate\Support\Facades\Auth; class LicenseImporter extends ItemImporter { @@ -73,14 +71,16 @@ class LicenseImporter extends ItemImporter if ($license->seats > 0) { $checkout_target = $this->item['checkout_target']; $asset = Asset::where('asset_tag', $asset_tag)->first(); - $targetLicense = $license->licenseSeats()->first(); + $targetLicense = $license->freeSeat(); if ($checkout_target) { $targetLicense->assigned_to = $checkout_target->id; + $targetLicense->user_id = Auth::id(); if ($asset) { $targetLicense->asset_id = $asset->id; } $targetLicense->save(); } elseif ($asset) { + $targetLicense->user_id = Auth::id(); $targetLicense->asset_id = $asset->id; $targetLicense->save(); } diff --git a/app/Importer/UserImporter.php b/app/Importer/UserImporter.php index 761efe69bb..4fcf221cba 100644 --- a/app/Importer/UserImporter.php +++ b/app/Importer/UserImporter.php @@ -2,7 +2,7 @@ namespace App\Importer; -use App\Helpers\Helper; +use App\Models\Department; use App\Models\User; use App\Notifications\WelcomeNotification; @@ -18,6 +18,8 @@ use App\Notifications\WelcomeNotification; class UserImporter extends ItemImporter { protected $users; + protected $send_welcome = false; + public function __construct($filename) { parent::__construct($filename); @@ -43,7 +45,6 @@ class UserImporter extends ItemImporter $this->item['username'] = $this->findCsvMatch($row, 'username'); $this->item['first_name'] = $this->findCsvMatch($row, 'first_name'); $this->item['last_name'] = $this->findCsvMatch($row, 'last_name'); - \Log::debug('UserImporter.php Name: '.$this->item['first_name'].' '.$this->item['last_name'].' ('.$this->item['username'].')'); $this->item['email'] = $this->findCsvMatch($row, 'email'); $this->item['phone'] = $this->findCsvMatch($row, 'phone_number'); $this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle'); @@ -52,15 +53,14 @@ class UserImporter extends ItemImporter $this->item['state'] = $this->findCsvMatch($row, 'state'); $this->item['country'] = $this->findCsvMatch($row, 'country'); $this->item['activated'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')) == 1) ? '1' : 0; - - \Log::debug('UserImporter.php Activated: '.$this->findCsvMatch($row, 'activated')); - \Log::debug('UserImporter.php Activated fetchHumanBoolean: '. $this->fetchHumanBoolean($this->findCsvMatch($row, 'activated'))); - $this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num'); - $this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department')) ? $this->createOrFetchDepartment($this->findCsvMatch($row, 'department')) : null; - $this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name')) ? $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name')) : null; - + $this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department')); + $this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name')); + $user_department = $this->findCsvMatch($row, 'department'); + if ($this->shouldUpdateField($user_department)) { + $this->item["department_id"] = $this->createOrFetchDepartment($user_department); + } $user = User::where('username', $this->item['username'])->first(); if ($user) { if (!$this->updating) { @@ -79,13 +79,14 @@ class UserImporter extends ItemImporter // This needs to be applied after the update logic, otherwise we'll overwrite user passwords // Issue #5408 - $this->item['password'] = $this->tempPassword; + $this->item['password'] = bcrypt($this->tempPassword); $this->log("No matching user, creating one"); $user = new User(); $user->fill($this->sanitizeItemForStoring($user)); if ($user->save()) { + // $user->logCreate('Imported using CSV Importer'); $this->log("User " . $this->item["name"] . ' was created'); if(($user->email) && ($user->activated=='1')) { @@ -100,7 +101,6 @@ class UserImporter extends ItemImporter if ($this->send_welcome) { $user->notify(new WelcomeNotification($data)); } - } $user = null; $this->item = null; @@ -110,4 +110,35 @@ class UserImporter extends ItemImporter $this->logError($user, 'User'); return; } + + /** + * Fetch an existing department, or create new if it doesn't exist + * + * @author Daniel Melzter + * @since 5.0 + * @param $department_name string + * @return int id of department created/found + */ + public function createOrFetchDepartment($department_name) + { + $department = Department::where(['name' => $department_name])->first(); + if ($department) { + $this->log('A matching department ' . $department_name . ' already exists'); + return $department->id; + } + $department = new department(); + $department->name = $department_name; + $department->user_id = $this->user_id; + + if ($department->save()) { + $this->log('department ' . $department_name . ' was created'); + return $department->id; + } + $this->logError($department, 'Company'); + return null; + } + + public function sendWelcome($send = true) { + $this->send_welcome = $send; + } } diff --git a/app/Importer/import_mappings.md b/app/Importer/import_mappings.md index c6ea3e2376..7899cf679a 100644 --- a/app/Importer/import_mappings.md +++ b/app/Importer/import_mappings.md @@ -33,6 +33,7 @@ | warranty months | warranty_months | Asset | | User Related Fields | assigned_to | Asset | | name | | | +| email | | | | username | | | | address | address | User | | city | city | User | diff --git a/app/LegacyEncrypter/McryptEncrypter.php b/app/LegacyEncrypter/McryptEncrypter.php index 90e92bf4ef..ac0a49fc58 100644 --- a/app/LegacyEncrypter/McryptEncrypter.php +++ b/app/LegacyEncrypter/McryptEncrypter.php @@ -3,10 +3,10 @@ namespace App\LegacyEncrypter; use Exception; -use RuntimeException; use Illuminate\Contracts\Encryption\DecryptException; -use Illuminate\Contracts\Encryption\EncryptException; use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; +use Illuminate\Contracts\Encryption\EncryptException; +use RuntimeException; /** * @deprecated since version 5.1. Use Illuminate\Encryption\Encrypter. diff --git a/app/Listeners/CheckoutableListener.php b/app/Listeners/CheckoutableListener.php new file mode 100644 index 0000000000..ce38d7253c --- /dev/null +++ b/app/Listeners/CheckoutableListener.php @@ -0,0 +1,211 @@ +checkedOutTo instanceof User) { + return; + } + + /** + * Make a checkout acceptance and attach it in the notification + */ + $acceptance = $this->getCheckoutAcceptance($event); + + if(!$event->checkedOutTo->locale){ + Notification::locale(Setting::getSettings()->locale)->send( + $this->getNotifiables($event), + $this->getCheckoutNotification($event, $acceptance) + ); + } else { + Notification::send( + $this->getNotifiables($event), + $this->getCheckoutNotification($event, $acceptance) + ); + } + } + + /** + * Notify the user about the checked in checkoutable + */ + public function onCheckedIn($event) { + + \Log::debug('checkin fired'); + + /** + * When the item wasn't checked out to a user, we can't send notifications + */ + if(!$event->checkedOutTo instanceof User) { + \Log::debug('checked out to not a user'); + return; + } + + /** + * Send the appropriate notification + */ + + + \Log::debug('checked out to a user'); + if(!$event->checkedOutTo->locale){ + \Log::debug('Use default settings locale'); + Notification::locale(Setting::getSettings()->locale)->send( + $this->getNotifiables($event), + $this->getCheckinNotification($event) + ); + } else { + \Log::debug('Use user locale? I do not think this works as expected yet'); + // \Log::debug(print_r($this->getNotifiables($event), true)); + Notification::send( + $this->getNotifiables($event), + $this->getCheckinNotification($event) + ); + } + } + + /** + * Generates a checkout acceptance + * @param Event $event + * @return mixed + */ + private function getCheckoutAcceptance($event) { + if (!$event->checkoutable->requireAcceptance()) { + return null; + } + + $acceptance = new CheckoutAcceptance; + $acceptance->checkoutable()->associate($event->checkoutable); + $acceptance->assignedTo()->associate($event->checkedOutTo); + $acceptance->save(); + + return $acceptance; + } + + /** + * Gets the entities to be notified of the passed event + * + * @param Event $event + * @return Collection + */ + private function getNotifiables($event) { + $notifiables = collect(); + + /** + * Notify the user who checked out the item + */ + $notifiables->push($event->checkedOutTo); + + /** + * Notify Admin users if the settings is activated + */ + if (Setting::getSettings()->admin_cc_email != '') { + $notifiables->push(new AdminRecipient()); + } + + return $notifiables; + } + + /** + * Get the appropriate notification for the event + * + * @param CheckoutableCheckedIn $event + * @return Notification + */ + private function getCheckinNotification($event) { + + // $model = get_class($event->checkoutable); + + + + $notificationClass = null; + + switch (get_class($event->checkoutable)) { + case Accessory::class: + $notificationClass = CheckinAccessoryNotification::class; + break; + case Asset::class: + $notificationClass = CheckinAssetNotification::class; + break; + case LicenseSeat::class: + $notificationClass = CheckinLicenseSeatNotification::class; + break; + } + + \Log::debug('Notification class: '.$notificationClass); + return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note); + } + + /** + * Get the appropriate notification for the event + * + * @param CheckoutableCheckedIn $event + * @param CheckoutAcceptance $acceptance + * @return Notification + */ + private function getCheckoutNotification($event, $acceptance) { + $notificationClass = null; + + switch (get_class($event->checkoutable)) { + case Accessory::class: + $notificationClass = CheckoutAccessoryNotification::class; + break; + case Asset::class: + $notificationClass = CheckoutAssetNotification::class; + break; + case Consumable::class: + $notificationClass = CheckoutConsumableNotification::class; + break; + case LicenseSeat::class: + $notificationClass = CheckoutLicenseSeatNotification::class; + break; + } + + return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note); + } + + /** + * Register the listeners for the subscriber. + * + * @param Illuminate\Events\Dispatcher $events + */ + public function subscribe($events) + { + $events->listen( + 'App\Events\CheckoutableCheckedIn', + 'App\Listeners\CheckoutableListener@onCheckedIn' + ); + + $events->listen( + 'App\Events\CheckoutableCheckedOut', + 'App\Listeners\CheckoutableListener@onCheckedOut' + ); + } + +} \ No newline at end of file diff --git a/app/Listeners/LogFailedLogin.php b/app/Listeners/LogFailedLogin.php index 4f484323e5..663b4559c1 100644 --- a/app/Listeners/LogFailedLogin.php +++ b/app/Listeners/LogFailedLogin.php @@ -2,10 +2,9 @@ namespace App\Listeners; -use Illuminate\Auth\Events\Failed; -use Illuminate\Http\Request; -use DB; use Carbon\Carbon; +use DB; +use Illuminate\Auth\Events\Failed; class LogFailedLogin { diff --git a/app/Listeners/LogListener.php b/app/Listeners/LogListener.php new file mode 100644 index 0000000000..5e9445183f --- /dev/null +++ b/app/Listeners/LogListener.php @@ -0,0 +1,87 @@ +checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date); + } + + public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event) { + $event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout); + } + + public function onCheckoutAccepted(CheckoutAccepted $event) { + $logaction = new Actionlog(); + + $logaction->item()->associate($event->acceptance->checkoutable); + $logaction->target()->associate($event->acceptance->assignedTo); + $logaction->accept_signature = $event->acceptance->signature_filename; + $logaction->action_type = 'accepted'; + + // TODO: log the actual license seat that was checked out + if($event->acceptance->checkoutable instanceof LicenseSeat) { + $logaction->item()->associate($event->acceptance->checkoutable->license); + } + + $logaction->save(); + } + + public function onCheckoutDeclined(CheckoutDeclined $event) { + $logaction = new Actionlog(); + $logaction->item()->associate($event->acceptance->checkoutable); + $logaction->target()->associate($event->acceptance->assignedTo); + $logaction->accept_signature = $event->acceptance->signature_filename; + $logaction->action_type = 'declined'; + + // TODO: log the actual license seat that was checked out + if($event->acceptance->checkoutable instanceof LicenseSeat) { + $logaction->item()->associate($event->acceptance->checkoutable->license); + } + + $logaction->save(); + } + + /** + * Register the listeners for the subscriber. + * + * @param Illuminate\Events\Dispatcher $events + */ + public function subscribe($events) + { + $list = [ + 'CheckoutableCheckedIn', + 'CheckoutableCheckedOut', + 'CheckoutAccepted', + 'CheckoutDeclined', + ]; + + foreach($list as $event) { + $events->listen( + 'App\Events\\' . $event, + 'App\Listeners\LogListener@on' . $event + ); + } + } + +} diff --git a/app/Listeners/LogSuccessfulLogin.php b/app/Listeners/LogSuccessfulLogin.php index 78450b8041..0fab5d00f6 100644 --- a/app/Listeners/LogSuccessfulLogin.php +++ b/app/Listeners/LogSuccessfulLogin.php @@ -2,10 +2,9 @@ namespace App\Listeners; -use Illuminate\Auth\Events\Login; -use Illuminate\Http\Request; -use DB; use Carbon\Carbon; +use DB; +use Illuminate\Auth\Events\Login; class LogSuccessfulLogin { diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index 944304d806..25c835d382 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -1,12 +1,12 @@ ['name'], 'location' => ['name'] ]; - - /** - * Set static properties to determine which checkout/checkin handlers we should use - */ - public static $checkoutClass = CheckoutAccessoryNotification::class; - public static $checkinClass = CheckinAccessoryNotification::class; - /** * Accessory validation rules @@ -101,13 +96,26 @@ class Accessory extends SnipeModel - + /** + * Establishes the accessory -> supplier relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - + + /** + * Sets the requestable attribute on the accessory + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return void + */ public function setRequestableAttribute($value) { if ($value == '') { @@ -117,62 +125,176 @@ class Accessory extends SnipeModel return; } + /** + * Establishes the accessory -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the accessory -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the accessory -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id')->where('category_type', '=', 'accessory'); } /** - * Get action logs for this accessory - */ + * Returns the action logs associated with the accessory + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Accessory::class)->orderBy('created_at', 'desc')->withTrashed(); } + /** + * Get the LAST checkout for this accessory. + * + * This is kinda gross, but is necessary for how the accessory + * pivot stuff works for now. + * + * It looks like we should be able to use ->first() here and + * return an object instead of a collection, but we actually + * cannot. + * + * In short, you cannot execute the query defined when you're eager loading. + * and in order to avoid 1001 query problems when displaying the most + * recent checkout note, we have to eager load this. + * + * This means we technically return a collection of one here, and then + * in the controller, we convert that collection to an array, so we can + * use it in the transformer to display only the notes of the LAST + * checkout. + * + * It's super-mega-assy, but it's the best I could do for now. + * + * @author A. Gianotto + * @since v5.0.0 + * + * @see \App\Http\Controllers\Api\AccessoriesController\checkedout() + * + */ + public function lastCheckout() + { + return $this->assetlog()->where('action_type','=','checkout')->take(1); + } + + + /** + * Sets the full image url + * + * @todo this should probably be moved out of the model and into a + * presenter or service provider + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/accessories/'.$this->image; + return Storage::disk('public')->url(app('accessories_upload_path').$this->image); } return false; } + /** + * Establishes the accessory -> users relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function users() { return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id')->withTrashed(); } + /** + * Checks whether or not the accessory has users + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ public function hasUsers() { return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->count(); } + /** + * Establishes the accessory -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Determins whether or not an email should be sent for checkin/checkout of this + * accessory based on the category it belongs to. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; } + /** + * Determines whether or not the accessory should require the user to + * accept it via email. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getEula() { @@ -186,6 +308,13 @@ class Accessory extends SnipeModel return null; } + /** + * Check how many items of an accessory remain + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ public function numRemaining() { $checkedout = $this->users->count(); diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php index b2945b8d13..7540568387 100755 --- a/app/Models/Actionlog.php +++ b/app/Models/Actionlog.php @@ -2,11 +2,9 @@ namespace App\Models; use App\Models\Traits\Searchable; use App\Presenters\Presentable; -use Illuminate\Database\Eloquent\Model; +use Carbon; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Auth; -use Response; -use Carbon; /** * Model for the Actionlog (the table that keeps a historical log of @@ -41,9 +39,15 @@ class Actionlog extends SnipeModel */ protected $searchableRelations = [ 'company' => ['name'] - ]; + ]; - // Overridden from Builder to automatically add the company + /** + * Override from Builder to automatically add the company + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function boot() { parent::boot(); @@ -60,17 +64,39 @@ class Actionlog extends SnipeModel } }); } - // Eloquent Relationships below + + + /** + * Establishes the actionlog -> item relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function item() { return $this->morphTo('item')->withTrashed(); } + /** + * Establishes the actionlog -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->hasMany('\App\Models\Company', 'id', 'company_id'); } + /** + * Establishes the actionlog -> item type relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function itemType() { @@ -80,6 +106,13 @@ class Actionlog extends SnipeModel return camel_case(class_basename($this->item_type)); } + /** + * Establishes the actionlog -> target type relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function targetType() { if ($this->target_type == User::class) { @@ -88,28 +121,14 @@ class Actionlog extends SnipeModel return camel_case(class_basename($this->target_type)); } - public function parseItemRoute() - { - if ($this->itemType() == "asset") { - $itemroute = 'assets'; - } elseif ($this->itemType() == "accessory") { - $itemroute = 'accessories'; - } elseif ($this->itemType()=="consumable") { - $itemroute = 'consumables'; - } elseif ($this->itemType()=="license") { - $itemroute = 'licenses'; - } elseif ($this->itemType()=="component") { - $itemroute = 'components'; - } else { - $itemroute = ''; - } - - return $itemroute; - } - - - + /** + * Establishes the actionlog -> uploads relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->morphTo('item') @@ -117,39 +136,62 @@ class Actionlog extends SnipeModel ->withTrashed(); } + /** + * Establishes the actionlog -> userlog relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function userlog() { return $this->target(); } + /** + * Establishes the actionlog -> user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo(User::class, 'user_id') ->withTrashed(); } + /** + * Establishes the actionlog -> target relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function target() { return $this->morphTo('target')->withTrashed(); } - public function childlogs() - { - return $this->hasMany('\App\Models\ActionLog', 'thread_id'); - } - - public function parentlog() - { - return $this->belongsTo('\App\Models\ActionLog', 'thread_id'); - } - + /** + * Establishes the actionlog -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed(); } + /** - * Check if the file exists, and if it does, force a download - **/ + * Check if the file exists, and if it does, force a download + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string | false + */ public function get_src($type = 'assets', $fieldname = 'filename') { if ($this->filename!='') { @@ -162,8 +204,12 @@ class Actionlog extends SnipeModel /** - * Get the parent category name - */ + * Saves the log record with the action type + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function logaction($actiontype) { @@ -176,6 +222,13 @@ class Actionlog extends SnipeModel } } + /** + * Calculate the number of days until the next audit + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int + */ public function daysUntilNextAudit($monthInterval = 12, $asset = null) { $now = Carbon::now(); @@ -192,6 +245,13 @@ class Actionlog extends SnipeModel return $next_audit_days; } + /** + * Calculate the date of the next audit + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Datetime + */ public function calcNextAuditDate($monthInterval = 12, $asset = null) { $last_audit_date = Carbon::parse($this->created_at); @@ -204,12 +264,12 @@ class Actionlog extends SnipeModel } /** - * getListingOfActionLogsChronologicalOrder - * - * @return mixed - * @author Vincent Sposato - * @version v1.0 - */ + * Gets action logs in chronological order, excluding uploads + * + * @author Vincent Sposato + * @since v1.0 + * @return \Illuminate\Database\Eloquent\Collection + */ public function getListingOfActionLogsChronologicalOrder() { diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 0b2511d0d2..9af62593d7 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -1,22 +1,22 @@ assigned_to = null; + $this->assigned_type = null; + $this->accepted = null; + $this->save(); + } /** @@ -69,6 +77,14 @@ class Asset extends Depreciable ]; + protected $casts = [ + 'model_id' => 'integer', + 'status_id' => 'integer', + 'company_id' => 'integer', + 'location_id' => 'integer', + 'rtd_company_id' => 'integer', + 'supplier_id' => 'integer', + ]; protected $rules = [ 'name' => 'max:255|nullable', @@ -79,13 +95,15 @@ class Asset extends Depreciable 'physical' => 'numeric|max:1|nullable', 'checkout_date' => 'date|max:10|min:10|nullable', 'checkin_date' => 'date|max:10|min:10|nullable', - 'supplier_id' => 'numeric|nullable', + 'supplier_id' => 'exists:suppliers,id|numeric|nullable', + 'location_id' => 'exists:locations,id|nullable', + 'rtd_location_id' => 'exists:locations,id|nullable', 'asset_tag' => 'required|min:1|max:255|unique_undeleted', 'status' => 'integer', 'serial' => 'unique_serial|nullable', 'purchase_cost' => 'numeric|nullable', - 'next_audit_date' => 'date|nullable', - 'last_audit_date' => 'date|nullable', + 'next_audit_date' => 'date|nullable', + 'last_audit_date' => 'date|nullable', ]; /** @@ -149,7 +167,32 @@ class Asset extends Depreciable 'model' => ['name', 'model_number'], 'model.category' => ['name'], 'model.manufacturer' => ['name'], - ]; + ]; + + + /** + * This handles the custom field validation for assets + * + * @var array + */ + public function save(array $params = []) + { + $settings = \App\Models\Setting::getSettings(); + + // I don't remember why we have this here? Asset tag would always be required, even if auto increment is on... + $this->rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required'; + + if($this->model_id != '') { + $model = AssetModel::find($this->model_id); + + if (($model) && ($model->fieldset)) { + $this->rules += $model->fieldset->validation_rules(); + } + } + + return parent::save($params); + } + public function getDisplayNameAttribute() { @@ -175,12 +218,26 @@ class Asset extends Depreciable return null; } + + /** + * Establishes the asset -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } - + /** + * Determines if an asset is available for checkout + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function availableForCheckout() { if ( @@ -193,8 +250,13 @@ class Asset extends Depreciable return false; } + /** - * Checkout asset + * Checks the asset out to the target + * + * @todo The admin parameter is never used. Can probably be removed. + * + * @author [A. Gianotto] [] * @param User $user * @param User $admin * @param Carbon $checkout_at @@ -202,13 +264,17 @@ class Asset extends Depreciable * @param string $note * @param null $name * @return bool + * @since [v3.0] + * @return boolean */ - //FIXME: The admin parameter is never used. Can probably be removed. public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null) { if (!$target) { return false; } + if ($this->is($target)) { + throw new CheckoutNotAllowed('You cannot check an asset out to itself.'); + } if ($expected_checkin) { $this->expected_checkin = $expected_checkin; @@ -233,27 +299,24 @@ class Asset extends Depreciable $this->location_id = $target->id; } } - - /** - * Does the user have to confirm that they accept the asset? - * - * If so, set the acceptance-status to "pending". - * This value is used in the unaccepted assets reports, for example - * - * @see https://github.com/snipe/snipe-it/issues/5772 - */ - if ($this->requireAcceptance() && $target instanceof User) { - $this->accepted = self::ACCEPTANCE_PENDING; - } if ($this->save()) { - $this->logCheckout($note, $target); + + event(new CheckoutableCheckedOut($this, $target, Auth::user(), $note)); + $this->increment('checkout_counter', 1); return true; } return false; } + /** + * Sets the detailedNameAttribute + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getDetailedNameAttribute() { if ($this->assignedto) { @@ -264,31 +327,54 @@ class Asset extends Depreciable return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . ($this->model) ? $this->model->name: ''; } - public function validationRules($id = '0') + /** + * Pulls in the validation rules + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return array + */ + public function validationRules() { return $this->rules; } /** - * Set depreciation relationship - */ + * Establishes the asset -> depreciation relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function depreciation() { return $this->model->belongsTo('\App\Models\Depreciation', 'depreciation_id'); } + /** * Get components assigned to this asset + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function components() { return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty')->withTrashed(); } - /** - * Get depreciation attribute from associated asset model - */ + + /** + * Get depreciation attribute from associated asset model + * + * @todo Is this still needed? + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function get_depreciation() { if (($this->model) && ($this->model->depreciation)) { @@ -296,9 +382,14 @@ class Asset extends Depreciable } } - /** - * Get uploads for this asset - */ + + /** + * Get uploads for this asset + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -308,29 +399,58 @@ class Asset extends Depreciable ->orderBy('created_at', 'desc'); } + /** + * Determines whether the asset is checked out to a user + * * Even though we allow allow for checkout to things beyond users * this method is an easy way of seeing if we are checked out to a user. - * @return mixed + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean */ public function checkedOutToUser() { return $this->assignedType() === self::USER; } + /** + * Get the target this asset is checked out to + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assignedTo() { return $this->morphTo('assigned', 'assigned_type', 'assigned_to'); } + /** + * Gets assets assigned to this asset + * + * Sigh. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assignedAssets() { return $this->morphMany('App\Models\Asset', 'assigned', 'assigned_type', 'assigned_to')->withTrashed(); } - /** - * Get the asset's location based on the assigned user - **/ + + /** + * Get the asset's location based on the assigned user + * + * @todo Refactor this if possible. It's awful. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \ArrayObject + */ public function assetLoc($iterations = 1,$first_asset = null) { if (!empty($this->assignedType())) { @@ -365,33 +485,58 @@ class Asset extends Depreciable return $this->defaultLoc; } + /** + * Gets the lowercased name of the type of target the asset is assigned to + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string + */ public function assignedType() { return strtolower(class_basename($this->assigned_type)); } - /** - * Get the asset's location based on default RTD location - **/ + + /** + * Get the asset's location based on default RTD location + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultLoc() { return $this->belongsTo('\App\Models\Location', 'rtd_location_id'); } - + /** + * Get the image URL of the asset. + * + * Check first to see if there is a specific image uploaded to the asset, + * and if not, check for an image uploaded to the asset model. + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return string | false + */ public function getImageUrl() { if ($this->image && !empty($this->image)) { - return url('/').'/uploads/assets/'.$this->image; + return Storage::disk('public')->url(app('assets_upload_path').e($this->image)); } elseif ($this->model && !empty($this->model->image)) { - return url('/').'/uploads/models/'.$this->model->image; + return Storage::disk('public')->url(app('models_upload_path').e($this->model->image)); } return false; } - /** - * Get action logs for this asset - */ + /** + * Get the asset's logs + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -401,7 +546,11 @@ class Asset extends Depreciable } /** - * Get checkouts + * Get the list of checkouts for this asset + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkouts() { @@ -411,7 +560,11 @@ class Asset extends Depreciable } /** - * Get checkins + * Get the list of checkins for this asset + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkins() { @@ -422,7 +575,11 @@ class Asset extends Depreciable } /** - * Get user requests + * Get the asset's user requests + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function userRequests() { @@ -433,71 +590,65 @@ class Asset extends Depreciable } - /** - * assetmaintenances - * Get improvements for this asset - * - * @return mixed - * @author Vincent Sposato - * @version v1.0 - */ + /** + * Get maintenances for this asset + * + * @author Vincent Sposato + * @since 1.0 + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetmaintenances() { return $this->hasMany('\App\Models\AssetMaintenance', 'asset_id') ->orderBy('created_at', 'desc'); } - /** - * Get action logs for this asset - */ + /** + * Get action logs history for this asset + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function adminuser() { return $this->belongsTo('\App\Models\User', 'user_id'); } - /** - * Get total assets - */ - public static function assetcount() - { - return Company::scopeCompanyables(Asset::where('physical', '=', '1')) - ->whereNull('deleted_at', 'and') - ->count(); - } - /** - * Get total assets not checked out - */ - public static function availassetcount() - { - return Asset::RTD() - ->whereNull('deleted_at') - ->count(); - } - /** - * Get requestable assets - */ - public static function getRequestable() - { - return Asset::Requestable() - ->whereNull('deleted_at') - ->count(); - } - - /** - * Get asset status - */ + /** + * Establishes the asset -> status relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetstatus() { return $this->belongsTo('\App\Models\Statuslabel', 'status_id'); } + /** + * Establishes the asset -> model relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function model() { return $this->belongsTo('\App\Models\AssetModel', 'model_id')->withTrashed(); } + /** + * Return the assets with a warranty expiring within x days + * + * @param $days + * @author [A. Gianotto] [] + * @since [v2.0] + * @return mixed + */ public static function getExpiringWarrantee($days = 30) { return Asset::where('archived', '=', '0') @@ -511,25 +662,50 @@ class Asset extends Depreciable ->get(); } - /** - * Get the license seat information - **/ + + /** + * Establishes the asset -> assigned licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->belongsToMany('\App\Models\License', 'license_seats', 'asset_id', 'license_id'); } + /** + * Establishes the asset -> status relationship + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenseseats() { return $this->hasMany('\App\Models\LicenseSeat', 'asset_id'); } + /** + * Establishes the asset -> aupplier relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - + /** + * Establishes the asset -> location relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); @@ -537,9 +713,13 @@ class Asset extends Depreciable - /** - * Get auto-increment - */ + /** + * Get the next autoincremented asset tag + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public static function autoincrement_asset() { $settings = \App\Models\Setting::getSettings(); @@ -562,10 +742,15 @@ class Asset extends Depreciable } } - /* - * Get the next base number for the auto-incrementer. We'll add the zerofill and - * prefixes on the fly as we generate the number + + /** + * Get the next base number for the auto-incrementer. * + * We'll add the zerofill and prefixes on the fly as we generate the number. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int */ public static function nextAutoIncrement($assets) { @@ -591,18 +776,40 @@ class Asset extends Depreciable - + /** + * Add zerofilling based on Settings + * + * We'll add the zerofill and prefixes on the fly as we generate the number. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string + */ public static function zerofill($num, $zerofill = 3) { return str_pad($num, $zerofill, '0', STR_PAD_LEFT); } - + /** + * Determine whether to send a checkin/checkout email based on + * asset model category + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function checkin_email() { return $this->model->category->checkin_email; } + /** + * Determine whether this asset requires acceptance by the assigned user + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { if (($this->model) && ($this->model->category)) { @@ -611,6 +818,14 @@ class Asset extends Depreciable } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { $Parsedown = new \Parsedown(); @@ -627,91 +842,92 @@ class Asset extends Depreciable return false; } + + /** + * ----------------------------------------------- + * BEGIN QUERY SCOPES + * ----------------------------------------------- + **/ + /** * Run additional, advanced searches. - * - * @param Illuminate\Database\Eloquent\Builder $query + * + * @param \Illuminate\Database\Eloquent\Builder $query * @param array $terms The search terms - * @return Illuminate\Database\Eloquent\Builder + * @return \Illuminate\Database\Eloquent\Builder */ public function advancedTextSearch(Builder $query, array $terms) { - - /** - * Assigned user - */ - $query = $query->leftJoin('users as assets_users',function ($leftJoin) { + /** + * Assigned user + */ + $query = $query->leftJoin('users as assets_users',function ($leftJoin) { $leftJoin->on("assets_users.id", "=", "assets.assigned_to") ->where("assets.assigned_type", "=", User::class); - }); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query - ->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%') - ->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%') - ->orWhere('assets_users.username', 'LIKE', '%'.$term.'%') - ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%", "%$term%"]); + $query = $query + ->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%') + ->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%') + ->orWhere('assets_users.username', 'LIKE', '%'.$term.'%') + ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%", "%$term%"]); - } + } - /** - * Assigned location - */ - $query = $query->leftJoin('locations as assets_locations',function ($leftJoin) { - $leftJoin->on("assets_locations.id","=","assets.assigned_to") - ->where("assets.assigned_type","=",Location::class); - }); + /** + * Assigned location + */ + $query = $query->leftJoin('locations as assets_locations',function ($leftJoin) { + $leftJoin->on("assets_locations.id","=","assets.assigned_to") + ->where("assets.assigned_type","=",Location::class); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query->orWhere('assets_locations.name', 'LIKE', '%'.$term.'%'); + $query = $query->orWhere('assets_locations.name', 'LIKE', '%'.$term.'%'); - } + } - /** - * Assigned assets - */ - $query = $query->leftJoin('assets as assigned_assets',function ($leftJoin) { - $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') - ->where('assets.assigned_type', '=', Asset::class); - }); + /** + * Assigned assets + */ + $query = $query->leftJoin('assets as assigned_assets',function ($leftJoin) { + $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') + ->where('assets.assigned_type', '=', Asset::class); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query->orWhere('assigned_assets.name', 'LIKE', '%'.$term.'%'); - - } + $query = $query->orWhere('assigned_assets.name', 'LIKE', '%'.$term.'%'); - return $query; + } + + return $query; } - /** - * ----------------------------------------------- - * BEGIN QUERY SCOPES - * ----------------------------------------------- - **/ - /** - * Query builder scope for hardware - * - * @param \Illuminate\Database\Query\Builder $query Query builder instance - * - * @return \Illuminate\Database\Query\Builder Modified query builder - */ + /** + * Query builder scope for hardware + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeHardware($query) { return $query->where('physical', '=', '1'); } - /** - * Query builder scope for pending assets - * - * @param \Illuminate\Database\Query\Builder $query Query builder instance - * - * @return \Illuminate\Database\Query\Builder Modified query builder - */ + /** + * Query builder scope for pending assets + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopePending($query) { @@ -763,7 +979,7 @@ class Asset extends Depreciable public function scopeRTD($query) { - return $query->whereNULL('assets.assigned_to') + return $query->whereNull('assets.assigned_to') ->whereHas('assetstatus', function ($query) { $query->where('deployable', '=', 1) ->where('pending', '=', 0) @@ -933,19 +1149,6 @@ class Asset extends Depreciable } - /** - * Query builder scope for Deleted assets - * - * @param \Illuminate\Database\Query\Builder $query Query builder instance - * - * @return \Illuminate\Database\Query\Builder Modified query builder - */ - - public function scopeDeleted($query) - { - return $query->whereNotNull('assets.deleted_at'); - } - /** * scopeInModelList * Get all assets in the provided listing of model ids @@ -1053,6 +1256,26 @@ class Asset extends Depreciable })->withTrashed()->whereNull("assets.deleted_at"); //workaround for laravel bug } + /** + * Query builder scope to search the department ID of users assigned to assets + * + * @author [A. Gianotto] [] + * @since [v5.0] + * @return string | false + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeCheckedOutToTargetInDepartment($query, $search) + { + return $query->leftJoin('users as assets_dept_users',function ($leftJoin) { + $leftJoin->on("assets_dept_users.id", "=", "assets.assigned_to") + ->where("assets.assigned_type", "=", User::class); + })->where(function ($query) use ($search) { + $query->where('assets_dept_users.department_id', '=', $search); + + })->withTrashed()->whereNull("assets.deleted_at"); //workaround for laravel bug + } + /** diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php index c63a7f6441..580aa18e04 100644 --- a/app/Models/AssetMaintenance.php +++ b/app/Models/AssetMaintenance.php @@ -4,7 +4,6 @@ namespace App\Models; use App\Helpers\Helper; use App\Models\Traits\Searchable; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Lang; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; @@ -22,7 +21,6 @@ class AssetMaintenance extends Model implements ICompanyableChild protected $dates = [ 'deleted_at', 'start_date' , 'completion_date']; protected $table = 'asset_maintenances'; - // Declaring rules for form validation protected $rules = [ 'asset_id' => 'required|integer', 'supplier_id' => 'required|integer', @@ -49,7 +47,10 @@ class AssetMaintenance extends Model implements ICompanyableChild * * @var array */ - protected $searchableRelations = []; + protected $searchableRelations = [ + 'asset' => ['name', 'asset_tag'], + 'asset.model' => ['name', 'model_number'], + ]; public function getCompanyableParents() @@ -156,6 +157,7 @@ class AssetMaintenance extends Model implements ICompanyableChild ->withTrashed(); } + /** * ----------------------------------------------- * BEGIN QUERY SCOPES @@ -166,10 +168,10 @@ class AssetMaintenance extends Model implements ICompanyableChild /** * Query builder scope to order on admin user * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderAdmin($query, $order) { @@ -181,10 +183,10 @@ class AssetMaintenance extends Model implements ICompanyableChild /** * Query builder scope to order on asset tag * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderByTag($query, $order) { @@ -195,14 +197,16 @@ class AssetMaintenance extends Model implements ICompanyableChild /** * Query builder scope to order on asset tag * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderByAssetName($query, $order) { return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id') ->orderBy('assets.name', $order); } + + } diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php index 9c18f522a5..1bb7902fda 100755 --- a/app/Models/AssetModel.php +++ b/app/Models/AssetModel.php @@ -1,12 +1,10 @@ 'required|min:1|max:255', + 'name' => 'required|min:1|max:255', 'model_number' => 'max:255|nullable', 'category_id' => 'required|integer|exists:categories,id', 'manufacturer_id' => 'required|integer|exists:manufacturers,id', - 'eol' => 'integer:min:0|max:240|nullable', + 'eol' => 'integer:min:0|max:240|nullable', ); /** @@ -87,47 +85,95 @@ class AssetModel extends SnipeModel 'depreciation' => ['name'], 'category' => ['name'], 'manufacturer' => ['name'], - ]; + ]; + + /** + * Establishes the model -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasMany('\App\Models\Asset', 'model_id'); } + /** + * Establishes the model -> category relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** + * Establishes the model -> depreciation relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function depreciation() { return $this->belongsTo('\App\Models\Depreciation', 'depreciation_id'); } - public function adminuser() - { - return $this->belongsTo('\App\Models\User', 'user_id'); - } + /** + * Establishes the model -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Establishes the model -> fieldset relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fieldset() { return $this->belongsTo('\App\Models\CustomFieldset', 'fieldset_id'); } + /** + * Establishes the model -> custom field default values relationship + * + * @author hannah tinkler + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultValues() { return $this->belongsToMany('\App\Models\CustomField', 'models_custom_fields')->withPivot('default_value'); } + /** + * Gets the full url for the image + * + * @todo this should probably be moved + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/models/'.$this->image; + return Storage::disk('public')->url(app('models_upload_path').$this->image); } return false; } @@ -138,17 +184,6 @@ class AssetModel extends SnipeModel * ----------------------------------------------- **/ - /** - * Query builder scope for Deleted assets - * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @return Illuminate\Database\Query\Builder Modified query builder - */ - - public function scopeDeleted($query) - { - return $query->whereNotNull('deleted_at'); - } /** * scopeInCategory diff --git a/app/Models/Category.php b/app/Models/Category.php index 7650cdde76..ae60a1d735 100755 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -2,11 +2,10 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; -use App\Models\SnipeModel; use App\Models\Traits\Searchable; use App\Presenters\Presentable; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Facades\Gate; use Watson\Validating\ValidatingTrait; /** @@ -26,6 +25,12 @@ class Category extends SnipeModel protected $table = 'categories'; protected $hidden = ['user_id','deleted_at']; + + protected $casts = [ + 'user_id' => 'integer', + ]; + + /** * Category validation rules */ @@ -65,46 +70,90 @@ class Category extends SnipeModel ]; use Searchable; - + /** * The attributes that should be included when searching the model. - * + * * @var array */ protected $searchableAttributes = ['name', 'category_type']; /** * The relations and their attributes that should be included when searching the model. - * + * * @var array */ protected $searchableRelations = []; - public function has_models() + + /** + * Checks if category can be deleted + * + * @author [Dan Meltzer] [] + * @since [v5.0] + * @return bool + */ + public function isDeletable() { - return $this->hasMany('\App\Models\AssetModel', 'category_id')->count(); + return (Gate::allows('delete', $this) + && ($this->itemCount() == 0)); } + /** + * Establishes the category -> accessories relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function accessories() { return $this->hasMany('\App\Models\Accessory'); } + /** + * Establishes the category -> licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->hasMany('\App\Models\License'); } + /** + * Establishes the category -> consumables relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function consumables() { return $this->hasMany('\App\Models\Consumable'); } + /** + * Establishes the category -> consumables relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function components() { return $this->hasMany('\App\Models\Component'); } + /** + * Get the number of items in the category + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return int + */ public function itemCount() { switch ($this->category_type) { @@ -120,16 +169,38 @@ class Category extends SnipeModel return '0'; } + /** + * Establishes the category -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'category_id', 'model_id'); } + /** + * Establishes the category -> models relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function models() { return $this->hasMany('\App\Models\AssetModel', 'category_id'); } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return string | null + */ public function getEula() { @@ -145,15 +216,22 @@ class Category extends SnipeModel } + /** - * scopeRequiresAcceptance + * ----------------------------------------------- + * BEGIN QUERY SCOPES + * ----------------------------------------------- + **/ + + /** + * Query builder scope for whether or not the category requires acceptance * - * @param $query - * - * @return mixed * @author Vincent Sposato - * @version v1.0 + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @return \Illuminate\Database\Query\Builder Modified query builder */ + public function scopeRequiresAcceptance($query) { diff --git a/app/Models/CheckoutAcceptance.php b/app/Models/CheckoutAcceptance.php new file mode 100644 index 0000000000..4bbe0af164 --- /dev/null +++ b/app/Models/CheckoutAcceptance.php @@ -0,0 +1,112 @@ +morphTo(); + } + + /** + * The user that the checkoutable was checked out to + * + * @return Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function assignedTo() { + return $this->belongsTo(User::class); + } + + /** + * Is this checkout acceptance pending? + * + * @return boolean + */ + public function isPending() { + return $this->accepted_at == null && $this->declined_at == null; + } + + /** + * Was the checkoutable checked out to this user? + * + * @param User $user + * @return boolean + */ + public function isCheckedOutTo(User $user) { + return $this->assignedTo->is($user); + } + + /** + * Accept the checkout acceptance + * + * @param string $signature_filename + */ + public function accept($signature_filename) { + $this->accepted_at = now(); + $this->signature_filename = $signature_filename; + $this->save(); + + /** + * Update state for the checked out item + */ + $this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename); + } + + /** + * Decline the checkout acceptance + * + * @param string $signature_filename + */ + public function decline($signature_filename) { + $this->declined_at = now(); + $this->signature_filename = $signature_filename; + $this->save(); + + /** + * Update state for the checked out item + */ + $this->checkoutable->declinedCheckout($this->assignedTo, $signature_filename); + } + + /** + * Filter checkout acceptences by the user + * @param Illuminate\Database\Eloquent\Builder $query + * @param User $user + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForUser(Builder $query, User $user) { + return $query->where('assigned_to_id', $user->id); + } + + /** + * Filter to only get pending acceptances + * @param Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopePending(Builder $query) { + return $query->whereNull('accepted_at')->whereNull('declined_at'); + } +} diff --git a/app/Models/CheckoutRequest.php b/app/Models/CheckoutRequest.php index df40618317..462af447e9 100644 --- a/app/Models/CheckoutRequest.php +++ b/app/Models/CheckoutRequest.php @@ -1,9 +1,8 @@ join('users as users_comp', 'users_comp.id', 'user_id')->where('users_comp.company_id', '=', $company_id); } - } public static function getIdFromInput($unescaped_input) @@ -148,6 +146,22 @@ final class Company extends SnipeModel Auth::user()->company_id == null); } + /** + * Checks if company can be deleted + * + * @author [Dan Meltzer] [] + * @since [v5.0] + * @return bool + */ + public function isDeletable() { + return Gate::allows('delete', $this) + && ($this->assets()->count() === 0) + && ($this->accessories()->count() === 0) + && ($this->consumables()->count() === 0) + && ($this->components()->count() === 0) + && ($this->users()->count() === 0); + } + public static function getIdForUser($unescaped_input) { if (!static::isFullMultipleCompanySupportEnabled() || Auth::user()->isSuperUser()) { diff --git a/app/Models/CompanyableChildScope.php b/app/Models/CompanyableChildScope.php index e569522b19..e83eb18ed8 100644 --- a/app/Models/CompanyableChildScope.php +++ b/app/Models/CompanyableChildScope.php @@ -1,9 +1,9 @@ 'required|min:3|max:255', - 'qty' => 'required|integer|min:1', - 'category_id' => 'required|integer', - 'company_id' => 'integer|nullable', + 'name' => 'required|min:3|max:255', + 'qty' => 'required|integer|min:1', + 'category_id' => 'required|integer|exists:categories,id', + 'company_id' => 'integer|nullable', + 'min_amt' => 'integer|min:0|nullable', 'purchase_date' => 'date|nullable', - 'purchase_cost' => 'numeric|nullable', + 'purchase_cost' => 'numeric|nullable', ); /** @@ -86,64 +80,118 @@ class Component extends SnipeModel 'category' => ['name'], 'company' => ['name'], 'location' => ['name'], - ]; + ]; + /** + * Establishes the component -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the component -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->belongsToMany('\App\Models\Asset', 'components_assets')->withPivot('id', 'assigned_qty', 'created_at', 'user_id'); } + /** + * Establishes the component -> admin user relationship + * + * @todo this is probably not needed - refactor + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function admin() { return $this->belongsTo('\App\Models\User', 'user_id'); } + /** + * Establishes the component -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } - + /** + * Establishes the component -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } /** - * Get action logs for this consumable - */ + * Establishes the component -> action logs relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Component::class)->orderBy('created_at', 'desc')->withTrashed(); } - - public function numRemaining() + /** + * Check how many items within a component are checked out + * + * @author [A. Gianotto] [] + * @since [v5.0] + * @return int + */ + public function numCheckedOut() { $checkedout = 0; - foreach ($this->assets as $checkout) { $checkedout += $checkout->pivot->assigned_qty; } + return $checkedout; + } - $total = $this->qty; - $remaining = $total - $checkedout; - return $remaining; - } + /** + * Check how many items within a component are remaining + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ + public function numRemaining() + { + return $this->qty - $this->numCheckedOut(); + } /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCategory($query, $order) { @@ -153,10 +201,10 @@ class Component extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -167,10 +215,10 @@ class Component extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index 0a310d77b1..14de8c6ebb 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -1,11 +1,12 @@ 'boolean' + 'requestable' => 'boolean', + 'category_id' => 'integer', + 'company_id' => 'integer', + 'qty' => 'integer', + 'min_amt' => 'integer', ]; - /** - * Set static properties to determine which checkout/checkin handlers we should use - */ - public static $checkoutClass = CheckoutConsumableNotification::class; - public static $checkinClass = null; /** @@ -88,8 +90,21 @@ class Consumable extends SnipeModel 'company' => ['name'], 'location' => ['name'], 'manufacturer' => ['name'], - ]; + ]; + /** + * Sets the attribute of whether or not the consumable is requestable + * + * This isn't really implemented yet, as you can't currently request a consumable + * however it will be implemented in the future, and we needed to include + * this method here so all of our polymorphic methods don't break. + * + * @todo Update this comment once it's been implemented + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function setRequestableAttribute($value) { if ($value == '') { @@ -99,73 +114,152 @@ class Consumable extends SnipeModel return; } + /** + * Establishes the consumable -> admin user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function admin() { return $this->belongsTo('\App\Models\User', 'user_id'); } + /** + * Establishes the component -> assignments relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function consumableAssignments() { return $this->hasMany('\App\Models\ConsumableAssignment'); } + /** + * Establishes the component -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the component -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Establishes the component -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the component -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** - * Get action logs for this consumable - */ + * Establishes the component -> action logs relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Consumable::class)->orderBy('created_at', 'desc')->withTrashed(); } + /** + * Gets the full image url for the consumable + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string | false + */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/consumables/'.$this->image; + return Storage::disk('public')->url(app('consumables_upload_path').$this->image); } return false; } - + /** + * Establishes the component -> users relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function users() { return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps(); } - public function hasUsers() - { - return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->count(); - } + /** + * Determine whether to send a checkin/checkout email based on + * asset model category + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; - } + } + /** + * Determine whether this asset requires acceptance by the assigned user + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { @@ -181,6 +275,13 @@ class Consumable extends SnipeModel } + /** + * Checks the number of available consumables + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int + */ public function numRemaining() { $checkedout = $this->users->count(); @@ -192,10 +293,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCategory($query, $order) { @@ -205,10 +306,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on location * - * @param Illuminate\Database\Query\Builder $query Query builder instance + * @param \Illuminate\Database\Query\Builder $query Query builder instance * @param text $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -218,10 +319,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on manufacturer * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManufacturer($query, $order) { @@ -232,10 +333,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index 4ea44fef90..3a5753b0a2 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -1,36 +1,52 @@ "", - "CUSTOM REGEX" => "", - "ALPHA" => "alpha", - "ALPHA-DASH" => "alpha_dash", - "NUMERIC" => "numeric", - "ALPHA-NUMERIC" => "alpha_num", - "EMAIL" => "email", - "DATE" => "date", - "URL" => "url", - "IP" => "ip", - "IPV4" => "ipv4", - "IPV6" => "ipv6", - "MAC" => "regex:/^[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}$/", - "BOOLEAN" => "boolean", + use ValidatingTrait, + UniqueUndeletedTrait; + + /** + * Custom field predfined formats + * + * @var array + */ + const PREDEFINED_FORMATS = [ + 'ANY' => '', + 'CUSTOM REGEX' => '', + 'ALPHA' => 'alpha', + 'ALPHA-DASH' => 'alpha_dash', + 'NUMERIC' => 'numeric', + 'ALPHA-NUMERIC' => 'alpha_num', + 'EMAIL' => 'email', + 'DATE' => 'date', + 'URL' => 'url', + 'IP' => 'ip', + 'IPV4' => 'ipv4', + 'IPV6' => 'ipv6', + 'MAC' => 'regex:/^[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}$/', + 'BOOLEAN' => 'boolean', + ]; + + public $guarded = [ + "id" ]; + /** + * Validation rules. + * At least empty array must be provided if using ValidatingTrait. + * + * @var array + */ + protected $rules = []; + /** * The attributes that are mass assignable. * @@ -46,13 +62,17 @@ class CustomField extends Model 'show_in_email', ]; - // This is confusing, since it's actually the custom fields table that - // we're usually modifying, but since we alter the assets table, we have to - // say that here, otherwise the new fields get added onto the custom fields - // table instead of the assets table. + /** + * This is confusing, since it's actually the custom fields table that + * we're usually modifying, but since we alter the assets table, we have to + * say that here, otherwise the new fields get added onto the custom fields + * table instead of the assets table. + * + * @author [Brady Wetherington] [] + * @since [v3.0] + */ public static $table_name = "assets"; - /** * Convert the custom field's name property to a db-safe string. * @@ -82,6 +102,7 @@ class CustomField extends Model */ public static function boot() { + parent::boot(); self::created(function ($custom_field) { // Column already exists on the assets table - nothing to do here. @@ -138,16 +159,37 @@ class CustomField extends Model }); } + /** + * Establishes the customfield -> fieldset relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fieldset() { return $this->belongsToMany('\App\Models\CustomFieldset'); } + /** + * Establishes the customfield -> admin user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User'); } + /** + * Establishes the customfield -> default values relationship + * + * @author Hannah Tinkler + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultValues() { return $this->belongsToMany('\App\Models\AssetModel', 'models_custom_fields')->withPivot('default_value'); @@ -169,11 +211,28 @@ class CustomField extends Model })->first(); } + /** + * Checks the format of the attribute + * + * @author [A. Gianotto] [] + * @param $value string + * @since [v3.0] + * @return boolean + */ public function check_format($value) { return preg_match('/^'.$this->attributes['format'].'$/', $value)===1; } + /** + * Gets the DB column name. + * + * @todo figure out if this is still needed? I don't know WTF it's for. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function db_column_name() { return $this->db_column; @@ -188,15 +247,16 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return string */ public function getFormatAttribute($value) { - foreach (self::$PredefinedFormats as $name => $pattern) { + foreach (self::PREDEFINED_FORMATS as $name => $pattern) { if ($pattern === $value || $name === $value) { return $name; } } + return $value; } @@ -205,12 +265,12 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return array */ public function setFormatAttribute($value) { - if (isset(self::$PredefinedFormats[$value])) { - $this->attributes['format']=self::$PredefinedFormats[$value]; + if (isset(self::PREDEFINED_FORMATS[$value])) { + $this->attributes['format']=self::PREDEFINED_FORMATS[$value]; } else { $this->attributes['format']=$value; } @@ -221,7 +281,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return array */ public function formatFieldValuesAsArray() { @@ -249,7 +309,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Boolean + * @return boolean */ public function isFieldDecryptable($string) { @@ -266,7 +326,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Boolean + * @return string */ public function convertUnicodeDbSlug($original = null) { @@ -287,7 +347,7 @@ class CustomField extends Model * @author [V. Cordes] [] * @param int $id * @since [v4.1.10] - * @return Array + * @return array */ public function validationRules() { @@ -298,9 +358,28 @@ class CustomField extends Model Rule::in(['text', 'listbox']) ], 'format' => [ - Rule::in(array_merge(array_keys(CustomField::$PredefinedFormats), CustomField::$PredefinedFormats)) + Rule::in(array_merge(array_keys(CustomField::PREDEFINED_FORMATS), CustomField::PREDEFINED_FORMATS)) ], 'field_encrypted' => "nullable|boolean" ]; } + + /** + * Check to see if there is a custom regex format type + * @see https://github.com/snipe/snipe-it/issues/5896 + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return string + */ + public function getFormatType() + { + if(stripos($this->format,'regex') === 0 && ($this->format !== self::PREDEFINED_FORMATS['MAC'])) { + return 'CUSTOM REGEX'; + } + + return $this->format; + } } diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index d0aa33aa23..157c193b41 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -1,16 +1,22 @@ "required|unique:custom_fieldsets" + /** + * Validation rules + * @var array + */ + public $rules = [ + "name" => "required|unique:custom_fieldsets" ]; /** @@ -21,24 +27,52 @@ class CustomFieldset extends Model * @var boolean */ protected $injectUniqueIdentifier = true; - use ValidatingTrait; - + + /** + * Establishes the fieldset -> field relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fields() { return $this->belongsToMany('\App\Models\CustomField')->withPivot(["required","order"])->orderBy("pivot_order"); } + /** + * Establishes the fieldset -> models relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function models() { return $this->hasMany('\App\Models\AssetModel', "fieldset_id"); } + /** + * Establishes the fieldset -> admin user relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User'); //WARNING - not all CustomFieldsets have a User!! } + /** + * Determine the validation rules we should apply based on the + * custom field format + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return array + */ public function validation_rules() { $rules=[]; diff --git a/app/Models/Department.php b/app/Models/Department.php index 14d7329b61..96aa4dd860 100644 --- a/app/Models/Department.php +++ b/app/Models/Department.php @@ -4,12 +4,7 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; use App\Models\Traits\Searchable; -use Illuminate\Database\Eloquent\Model; -use Log; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\SoftDeletes; -use App\Models\SnipeModel; -use App\Models\User; class Department extends SnipeModel { @@ -24,6 +19,12 @@ class Department extends SnipeModel use ValidatingTrait, UniqueUndeletedTrait; + protected $casts = [ + 'manager_id' => 'integer', + 'location_id' => 'integer', + 'company_id' => 'integer', + ]; + protected $rules = [ 'name' => 'required|max:255', 'location_id' => 'numeric|nullable', @@ -59,18 +60,27 @@ class Department extends SnipeModel * * @var array */ - protected $searchableRelations = []; - + protected $searchableRelations = []; + /** + * Establishes the department -> company relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** - * Even though we allow allow for checkout to things beyond users - * this method is an easy way of seeing if we are checked out to a user. - * @return mixed + * Establishes the department -> users relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function users() { @@ -79,15 +89,24 @@ class Department extends SnipeModel /** - * Return the manager in charge of the dept - * @return mixed - */ + * Establishes the department -> manager relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manager() { return $this->belongsTo('\App\Models\User', 'manager_id'); } - + /** + * Establishes the department -> location relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); diff --git a/app/Models/Depreciable.php b/app/Models/Depreciable.php index ee12a6506a..fde9530c45 100644 --- a/app/Models/Depreciable.php +++ b/app/Models/Depreciable.php @@ -1,10 +1,6 @@ get_depreciation()->months <= 0) { return $this->purchase_cost; } + $depreciation = 0; + $setting = Setting::getSettings(); + switch($setting->depreciation_method) { + case 'half_1': + $depreciation = $this->getHalfYearDepreciatedValue(true); + break; + + case 'half_2': + $depreciation = $this->getHalfYearDepreciatedValue(false); + break; + default: + $depreciation = $this->getLinearDepreciatedValue(); + } + return $depreciation; + } + + /** + * @return float|int + */ + + public function getLinearDepreciatedValue() + { // fraction of value left $months_remaining = $this->time_until_depreciated()->m + 12*$this->time_until_depreciated()->y; //UGlY $current_value = round(($months_remaining/ $this->get_depreciation()->months) * $this->purchase_cost, 2); @@ -60,6 +78,62 @@ class Depreciable extends SnipeModel return $current_value; } + /** + * @param onlyHalfFirstYear Boolean always applied only second half of the first year + * @return float|int + */ + public function getHalfYearDepreciatedValue($onlyHalfFirstYear = false) + { + // @link http://www.php.net/manual/en/class.dateinterval.php + $current_date = $this->getDateTime(); + $purchase_date = date_create($this->purchase_date); + $currentYear = $this->get_fiscal_year( $current_date ); + $purchaseYear = $this->get_fiscal_year( $purchase_date ); + $yearsPast = $currentYear - $purchaseYear; + $deprecationYears = ceil($this->get_depreciation()->months / 12); + if( $onlyHalfFirstYear ) { + $yearsPast -= 0.5; + } + else if( !$this->is_first_half_of_year($purchase_date) ) { + $yearsPast -= 0.5; + } + if( !$this->is_first_half_of_year($current_date) ) { + $yearsPast += 0.5; + } + + if($yearsPast >= $deprecationYears) { + $yearsPast = $deprecationYears; + } + else if($yearsPast < 0) { + $yearsPast = 0; + } + return round($yearsPast / $deprecationYears * $this->purchase_cost, 2); + } + + /** + * @param \DateTime $date + * @return int + */ + protected function get_fiscal_year($date) { + $year = intval($date->format('Y')); + // also, maybe it'll have to set fiscal year date + if($date->format('nj') === '1231') { + return $year; + } + else { + return $year - 1; + } + } + + /** + * @param \DateTime $date + * @return bool + */ + protected function is_first_half_of_year($date) { + $date0m0d = intval($date->format('md')); + return ($date0m0d < 601) || ($date0m0d >= 1231); + } + public function time_until_depreciated() { // @link http://www.php.net/manual/en/class.datetime.php @@ -81,4 +155,10 @@ class Depreciable extends SnipeModel date_add($date, date_interval_create_from_date_string($this->get_depreciation()->months . ' months')); return $date; //date_format($date, 'Y-m-d'); //don't bake-in format, for internationalization } + + // it's necessary for unit tests + protected function getDateTime($time = null) + { + return new \DateTime($time); + } } diff --git a/app/Models/Depreciation.php b/app/Models/Depreciation.php index e67d4d7fa4..c706f2f1e7 100755 --- a/app/Models/Depreciation.php +++ b/app/Models/Depreciation.php @@ -48,14 +48,28 @@ class Depreciation extends SnipeModel */ protected $searchableRelations = []; - - public function has_models() + /** + * Establishes the depreciation -> models relationship + * + * @author A. Gianotto + * @since [v5.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function models() { - return $this->hasMany('\App\Models\AssetModel', 'depreciation_id')->count(); + return $this->hasMany('\App\Models\AssetModel', 'depreciation_id'); } - public function has_licenses() + + /** + * Establishes the depreciation -> licenses relationship + * + * @author A. Gianotto + * @since [v5.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function licenses() { - return $this->hasMany('\App\Models\License', 'depreciation_id')->count(); + return $this->hasMany('\App\Models\License', 'depreciation_id'); } } diff --git a/app/Models/Group.php b/app/Models/Group.php index dce2018fec..25c2505101 100755 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -1,7 +1,6 @@ users relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function users() { return $this->belongsToMany('\App\Models\User', 'users_groups'); } - + /** + * Decode JSON permissions into array + * + * @author A. Gianotto + * @since [v1.0] + * @return array + */ public function decodePermissions() { return json_decode($this->permissions, true); diff --git a/app/Models/Ldap.php b/app/Models/Ldap.php deleted file mode 100644 index e135714fdf..0000000000 --- a/app/Models/Ldap.php +++ /dev/null @@ -1,295 +0,0 @@ - Settings. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return connection - */ - - public static function connectToLdap() - { - - $ldap_host = Setting::getSettings()->ldap_server; - $ldap_version = Setting::getSettings()->ldap_version; - $ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore; - $ldap_use_tls = Setting::getSettings()->ldap_tls; - - - // If we are ignoring the SSL cert we need to setup the environment variable - // before we create the connection - if ($ldap_server_cert_ignore=='1') { - putenv('LDAPTLS_REQCERT=never'); - } - - // If the user specifies where CA Certs are, make sure to use them - if (env("LDAPTLS_CACERT")) { - putenv("LDAPTLS_CACERT=".env("LDAPTLS_CACERT")); - } - - $connection = @ldap_connect($ldap_host); - - if (!$connection) { - throw new Exception('Could not connect to LDAP server at '.$ldap_host.'. Please check your LDAP server name and port number in your settings.'); - } - - // Needed for AD - ldap_set_option($connection, LDAP_OPT_REFERRALS, 0); - ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version); - ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20); - - if ($ldap_use_tls=='1') { - ldap_start_tls($connection); - } - - return $connection; - } - - - /** - * Binds/authenticates the user to LDAP, and returns their attributes. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @param $username - * @param $password - * @param bool|false $user - * @return bool true if the username and/or password provided are valid - * false if the username and/or password provided are invalid - * array of ldap_attributes if $user is true - * - */ - static function findAndBindUserLdap($username, $password) - { - $settings = Setting::getSettings(); - $connection = Ldap::connectToLdap(); - $ldap_username_field = $settings->ldap_username_field; - $baseDn = $settings->ldap_basedn; - $userDn = $ldap_username_field.'='.$username.','.$settings->ldap_basedn; - - if ($settings->is_ad =='1') { - // Check if they are using the userprincipalname for the username field. - // If they are, we can skip building the UPN to authenticate against AD - if ($ldap_username_field=='userprincipalname') { - $userDn = $username; - } else { - // In case they haven't added an AD domain - $userDn = ($settings->ad_domain != '') ? $username.'@'.$settings->ad_domain : $username.'@'.$settings->email_domain; - } - - } - - \Log::debug('Attempting to login using distinguished name:'.$userDn); - - - $filterQuery = $settings->ldap_auth_filter_query . $username; - - - if (!$ldapbind = @ldap_bind($connection, $userDn, $password)) { - if(!$ldapbind = Ldap::bindAdminToLdap($connection)){ - return false; - } - } - - if (!$results = ldap_search($connection, $baseDn, $filterQuery)) { - throw new Exception('Could not search LDAP: '); - } - - if (!$entry = ldap_first_entry($connection, $results)) { - return false; - } - - if (!$user = ldap_get_attributes($connection, $entry)) { - return false; - } - - return array_change_key_case($user); - - } - - - /** - * Binds/authenticates an admin to LDAP for LDAP searching/syncing. - * Here we also return a better error if the app key is donked. - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @param bool|false $user - * @return bool true if the username and/or password provided are valid - * false if the username and/or password provided are invalid - * - */ - static function bindAdminToLdap($connection) - { - - $ldap_username = Setting::getSettings()->ldap_uname; - - // Lets return some nicer messages for users who donked their app key, and disable LDAP - try { - $ldap_pass = \Crypt::decrypt(Setting::getSettings()->ldap_pword); - } catch (Exception $e) { - - throw new Exception('Your app key has changed! Could not decrypt LDAP password using your current app key, so LDAP authentication has been disabled. Login with a local account, update the LDAP password and re-enable it in Admin > Settings.'); - } - - - if (!$ldapbind = @ldap_bind($connection, $ldap_username, $ldap_pass)) { - throw new Exception('Could not bind to LDAP: '.ldap_error($connection)); - } - - } - - - /** - * Parse and map LDAP attributes based on settings - * - * @author [A. Gianotto] [] - * @since [v3.0] - * - * @param $ldapatttibutes - * @return array|bool - */ - static function parseAndMapLdapAttributes($ldapatttibutes) - { - //Get LDAP attribute config - $ldap_result_username = Setting::getSettings()->ldap_username_field; - $ldap_result_emp_num = Setting::getSettings()->ldap_emp_num; - $ldap_result_last_name = Setting::getSettings()->ldap_lname_field; - $ldap_result_first_name = Setting::getSettings()->ldap_fname_field; - $ldap_result_email = Setting::getSettings()->ldap_email; - - // Get LDAP user data - $item = array(); - $item["username"] = isset($ldapatttibutes[$ldap_result_username][0]) ? $ldapatttibutes[$ldap_result_username][0] : ""; - $item["employee_number"] = isset($ldapatttibutes[$ldap_result_emp_num][0]) ? $ldapatttibutes[$ldap_result_emp_num][0] : ""; - $item["lastname"] = isset($ldapatttibutes[$ldap_result_last_name][0]) ? $ldapatttibutes[$ldap_result_last_name][0] : ""; - $item["firstname"] = isset($ldapatttibutes[$ldap_result_first_name][0]) ? $ldapatttibutes[$ldap_result_first_name][0] : ""; - $item["email"] = isset($ldapatttibutes[$ldap_result_email][0]) ? $ldapatttibutes[$ldap_result_email][0] : "" ; - - return $item; - - - } - - /** - * Create user from LDAP attributes - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @param $ldapatttibutes - * @return array|bool - */ - static function createUserFromLdap($ldapatttibutes) - { - $item = Ldap::parseAndMapLdapAttributes($ldapatttibutes); - - - // Create user from LDAP data - if (!empty($item["username"])) { - $user = new User; - $user->first_name = $item["firstname"]; - $user->last_name = $item["lastname"]; - $user->username = $item["username"]; - $user->email = $item["email"]; - - if (Setting::getSettings()->ldap_pw_sync=='1') { - $user->password = bcrypt(Input::get("password")); - } else { - $pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 25); - $user->password = bcrypt($pass); - } - - $user->activated = 1; - $user->ldap_import = 1; - $user->notes = 'Imported on first login from LDAP'; - - if ($user->save()) { - return $user; - } else { - LOG::debug('Could not create user.'.$user->getErrors()); - throw new Exception("Could not create user: ".$user->getErrors()); - } - } - - return false; - - } - - /** - * Searches LDAP - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @param $ldapatttibutes - * @param $base_dn - * @return array|bool - */ - static function findLdapUsers($base_dn = null) - { - - $ldapconn = Ldap::connectToLdap(); - $ldap_bind = Ldap::bindAdminToLdap($ldapconn); - // Default to global base DN if nothing else is provided. - if (is_null($base_dn)) { - $base_dn = Setting::getSettings()->ldap_basedn; - } - $filter = Setting::getSettings()->ldap_filter; - - // Set up LDAP pagination for very large databases - $page_size = 500; - $cookie = ''; - $result_set = array(); - $global_count = 0; - - // Perform the search - do { - - // Paginate (non-critical, if not supported by server) - if (!$ldap_paging = @ldap_control_paged_result($ldapconn, $page_size, false, $cookie)) { - throw new Exception('Problem with your LDAP connection. Try checking the Use TLS setting in Admin > Settings. '); - } - - - $search_results = ldap_search($ldapconn, $base_dn, '('.$filter.')'); - - if (!$search_results) { - return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work. - } - - // Get results from page - $results = ldap_get_entries($ldapconn, $search_results); - if (!$results) { - return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work. - } - - // Add results to result set - $global_count += $results['count']; - $result_set = array_merge($result_set, $results); - - @ldap_control_paged_result_response($ldapconn, $search_results, $cookie); - - } while ($cookie !== null && $cookie != ''); - - - // Clean up after search - $result_set['count'] = $global_count; - $results = $result_set; - @ldap_control_paged_result($ldapconn, 0); - - return $results; - - - } -} diff --git a/app/Models/License.php b/app/Models/License.php index 136b38634c..649eb063f5 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -1,10 +1,6 @@ 'integer', + 'category_id' => 'integer', + 'company_id' => 'integer', + ]; + protected $rules = array( 'name' => 'required|string|min:3|max:255', 'seats' => 'required|min:1|max:999|integer', @@ -111,8 +108,14 @@ class License extends Depreciable 'manufacturer' => ['name'], 'company' => ['name'], 'category' => ['name'], - ]; + ]; + /** + * Update seat counts when the license is updated + * + * @author A. Gianotto + * @since [v3.0] + */ public static function boot() { parent::boot(); @@ -129,6 +132,13 @@ class License extends Depreciable }); } + /** + * Balance seat counts + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function adjustSeatCount($license, $oldSeats, $newSeats) { // If the seats haven't changed, continue on happily. @@ -182,15 +192,37 @@ class License extends Depreciable return true; } + /** + * Sets the attribute for whether or not the license is maintained + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setMaintainedAttribute($value) { $this->attributes['maintained'] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } + + /** + * Sets the reassignable attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setReassignableAttribute($value) { $this->attributes['reassignable'] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } + /** + * Sets expiration date attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setExpirationDateAttribute($value) { @@ -202,6 +234,13 @@ class License extends Depreciable $this->attributes['expiration_date'] = $value; } + /** + * Sets termination date attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return mixed + */ public function setTerminationDateAttribute($value) { if ($value == '' || $value == '0000-00-00') { @@ -212,31 +251,74 @@ class License extends Depreciable $this->attributes['termination_date'] = $value; } + /** + * Establishes the license -> company relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the license -> category relationship + * + * @author A. Gianotto + * @since [v4.4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** + * Establishes the license -> manufacturer relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Determine whether the user should be emailed on checkin/checkout + * + * @author A. Gianotto + * @since [v2.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; } + /** + * Determine whether the user should be required to accept the license + * + * @author A. Gianotto + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { $Parsedown = new \Parsedown(); @@ -251,7 +333,11 @@ class License extends Depreciable } /** - * Get the assigned user + * Establishes the license -> assigned user relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assignedusers() { @@ -259,8 +345,12 @@ class License extends Depreciable } /** - * Get asset logs for this asset - */ + * Establishes the license -> action logs relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -269,8 +359,12 @@ class License extends Depreciable } /** - * Get uploads for this asset - */ + * Establishes the license -> action logs -> uploads relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -282,16 +376,26 @@ class License extends Depreciable /** - * Get admin user for this asset - */ + * Establishes the license -> admin user relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function adminuser() { return $this->belongsTo('\App\Models\User', 'user_id'); } /** - * Get total licenses - */ + * Returns the total number of all license seats + * + * @todo this can probably be refactored at some point. We don't need counting methods. + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public static function assetcount() { return LicenseSeat::whereNull('deleted_at') @@ -300,8 +404,14 @@ class License extends Depreciable /** - * Get total licenses - */ + * Return the number of seats for this asset + * + * @todo this can also probably be refactored at some point. + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function totalSeatsByLicenseID() { return LicenseSeat::where('license_id', '=', $this->id) @@ -309,12 +419,28 @@ class License extends Depreciable ->count(); } - // We do this to eager load the "count" of seats from the controller. Otherwise calling "count()" on each model results in n+1 + /** + * Establishes the license -> seat relationship + * + * We do this to eager load the "count" of seats from the controller. + * Otherwise calling "count()" on each model results in n+1 sadness. + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenseSeatsRelation() { return $this->hasMany(LicenseSeat::class)->whereNull('deleted_at')->selectRaw('license_id, count(*) as count')->groupBy('license_id'); } + /** + * Sets the license seat count attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public function getLicenseSeatsCountAttribute() { if ($this->licenseSeatsRelation->first()) { @@ -325,8 +451,12 @@ class License extends Depreciable } /** - * Get total licenses not checked out - */ + * Returns the number of total available seats across all licenses + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public static function availassetcount() { return LicenseSeat::whereNull('assigned_to') @@ -336,7 +466,11 @@ class License extends Depreciable } /** - * Get the number of available seats + * Returns the number of total available seats for this license + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function availCount() { @@ -346,6 +480,13 @@ class License extends Depreciable ->whereNull('deleted_at'); } + /** + * Sets the available seats attribute + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed + */ public function getAvailSeatsCountAttribute() { if ($this->availCount->first()) { @@ -356,8 +497,11 @@ class License extends Depreciable } /** - * Get the number of assigned seats + * Retuns the number of assigned seats for this asset * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assignedCount() { @@ -367,9 +511,15 @@ class License extends Depreciable }); } + /** + * Sets the assigned seats attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function getAssignedSeatsCountAttribute() { - // dd($this->licenseSeatsRelation->first()); if ($this->assignedCount->first()) { return $this->assignedCount->first()->count; } @@ -377,6 +527,13 @@ class License extends Depreciable return 0; } + /** + * Calculates the number of remaining seats + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function remaincount() { $total = $this->licenseSeatsCount; @@ -386,7 +543,11 @@ class License extends Depreciable } /** - * Get the total number of seats + * Returns the total number of seats for this license + * + * @author A. Gianotto + * @since [v1.0] + * @return int */ public function totalcount() { @@ -397,21 +558,37 @@ class License extends Depreciable } /** - * Get license seat data + * Establishes the license -> seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function licenseseats() { return $this->hasMany('\App\Models\LicenseSeat'); } + /** + * Establishes the license -> supplier relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - /* - * Get the next available free seat - used by + + /** + * Gets the next available free seat - used by * the API to populate next_seat + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed */ public function freeSeat() { @@ -425,15 +602,28 @@ class License extends Depreciable ->first(); } - /* - * Get the next available free seat - used by - * the API to populate next_seat - */ + + /** + * Establishes the license -> free seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function freeSeats() { return $this->hasMany('\App\Models\LicenseSeat')->whereNull('assigned_to')->whereNull('deleted_at')->whereNull('asset_id'); } + /** + * Returns expiring licenses + * + * @todo should refactor. I don't like get() in model methods + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function getExpiringLicenses($days = 60) { @@ -449,10 +639,10 @@ class License extends Depreciable /** * Query builder scope to order on manufacturer * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManufacturer($query, $order) { @@ -464,7 +654,7 @@ class License extends Depreciable * Query builder scope to order on supplier * * @param \Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param string $order Order * * @return \Illuminate\Database\Query\Builder Modified query builder */ @@ -477,10 +667,10 @@ class License extends Depreciable /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance + * @param \Illuminate\Database\Query\Builder $query Query builder instance * @param text $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/LicenseSeat.php b/app/Models/LicenseSeat.php index 26a34f1df1..590409f772 100755 --- a/app/Models/LicenseSeat.php +++ b/app/Models/LicenseSeat.php @@ -1,48 +1,92 @@ + * @since [v4.0] + * @return boolean + */ + public function requireAcceptance() + { + return $this->license->category->require_acceptance; + } + + public function getEula() { + return $this->license->getEula(); + } + + /** + * Establishes the seat -> license relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function license() { return $this->belongsTo('\App\Models\License', 'license_id'); } + /** + * Establishes the seat -> assignee relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User', 'assigned_to')->withTrashed(); } + /** + * Establishes the seat -> asset relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function asset() { return $this->belongsTo('\App\Models\Asset', 'asset_id')->withTrashed(); } + /** + * Determines the assigned seat's location based on user + * or asset its assigned to + * + * @author A. Gianotto + * @since [v4.0] + * @return string + */ public function location() { if (($this->user) && ($this->user->location)) { diff --git a/app/Models/Location.php b/app/Models/Location.php index ff36010341..dd1a8c5a43 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -7,10 +7,11 @@ use App\Models\SnipeModel; use App\Models\Traits\Searchable; use App\Models\User; use App\Presenters\Presentable; +use DB; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Facades\Gate; use Watson\Validating\ValidatingTrait; -use DB; class Location extends SnipeModel { @@ -20,15 +21,21 @@ class Location extends SnipeModel protected $dates = ['deleted_at']; protected $table = 'locations'; protected $rules = array( - 'name' => 'required|min:2|max:255|unique_undeleted', - 'city' => 'min:2|max:255|nullable', - 'country' => 'min:2|max:2|nullable', - 'address' => 'max:80|nullable', - 'address2' => 'max:80|nullable', - 'zip' => 'min:3|max:10|nullable', - 'manager_id' => 'exists:users,id|nullable' + 'name' => 'required|min:2|max:255|unique_undeleted', + 'city' => 'min:2|max:255|nullable', + 'country' => 'min:2|max:2|nullable', + 'address' => 'max:80|nullable', + 'address2' => 'max:80|nullable', + 'zip' => 'min:3|max:10|nullable', + 'manager_id' => 'exists:users,id|nullable', + 'parent_id' => 'nullable|exists:locations,id|different:id', ); + protected $casts = [ + 'parent_id' => 'integer', + 'manager_id' => 'integer', + ]; + /** * Whether the model should inject it's identifier to the unique * validation rules before attempting validation. If this property @@ -80,6 +87,14 @@ class Location extends SnipeModel 'parent' => ['name'] ]; + public function isDeletable() + { + return Gate::allows('delete', $this) + && ($this->assignedAssets()->count()===0) + && ($this->assets()->count()===0) + && ($this->users()->count()===0); + } + public function users() { return $this->hasMany('\App\Models\User', 'location_id'); diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php index ccf5fdfc8a..501b5057ca 100644 --- a/app/Models/Loggable.php +++ b/app/Models/Loggable.php @@ -2,20 +2,9 @@ namespace App\Models; -use App\Models\Actionlog; -use App\Models\Asset; -use App\Models\CheckoutRequest; -use App\Models\User; -use App\Notifications\CheckinAssetNotification; use App\Notifications\AuditNotification; -use App\Notifications\CheckoutAssetNotification; -use App\Notifications\CheckoutAccessoryNotification; -use App\Notifications\CheckinAccessoryNotification; -use App\Notifications\CheckoutConsumableNotification; -use App\Notifications\CheckoutLicenseNotification; -use App\Notifications\CheckinLicenseNotification; use Illuminate\Support\Facades\Auth; - +use App\Models\Setting; trait Loggable { @@ -36,9 +25,8 @@ trait Loggable * @since [v3.4] * @return \App\Models\Actionlog */ - public function logCheckout($note, $target /* What are we checking out to? */) + public function logCheckout($note, $target, $action_date = null) { - $settings = Setting::getSettings(); $log = new Actionlog; $log = $this->determineLogItemType($log); if (Auth::user()) { @@ -69,31 +57,14 @@ trait Loggable } $log->note = $note; + $log->action_date = $action_date; + + if (!$log->action_date) { + $log->action_date = date('Y-m-d H:i:s'); + } + $log->logaction('checkout'); - $params = [ - 'item' => $log->item, - 'target_type' => $log->target_type, - 'target' => $target, - 'admin' => $log->user, - 'note' => $note, - 'log_id' => $log->id, - 'settings' => $settings, - ]; - - $checkoutClass = null; - - if (method_exists($target, 'notify')) { - $target->notify(new static::$checkoutClass($params)); - } - - // Send to the admin, if settings dictate - $recipient = new \App\Models\Recipients\AdminRecipient(); - - if (($settings->admin_cc_email!='') && (static::$checkoutClass!='')) { - $recipient->notify(new static::$checkoutClass($params)); - } - return $log; } @@ -118,7 +89,7 @@ trait Loggable * @since [v3.4] * @return \App\Models\Actionlog */ - public function logCheckin($target, $note) + public function logCheckin($target, $note, $action_date = null) { $settings = Setting::getSettings(); $log = new Actionlog; @@ -135,7 +106,6 @@ trait Loggable if (static::class == Asset::class) { if ($asset = Asset::find($log->item_id)) { - \Log::debug('Increment the checkin count for asset: '.$log->item_id); $asset->increment('checkin_counter', 1); } } @@ -152,38 +122,38 @@ trait Loggable $log->logaction('checkin from'); - $params = [ - 'target' => $target, - 'item' => $log->item, - 'admin' => $log->user, - 'note' => $note, - 'target_type' => $log->target_type, - 'settings' => $settings, - ]; - - - $checkinClass = null; - - if (method_exists($target, 'notify')) { - try { - $target->notify(new static::$checkinClass($params)); - } catch (\Exception $e) { - \Log::debug($e); - } - - } - - // Send to the admin, if settings dictate - $recipient = new \App\Models\Recipients\AdminRecipient(); - - if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) { - try { - $recipient->notify(new static::$checkinClass($params)); - } catch (\Exception $e) { - \Log::debug($e); - } - - } +// $params = [ +// 'target' => $target, +// 'item' => $log->item, +// 'admin' => $log->user, +// 'note' => $note, +// 'target_type' => $log->target_type, +// 'settings' => $settings, +// ]; +// +// +// $checkinClass = null; +// +// if (method_exists($target, 'notify')) { +// try { +// $target->notify(new static::$checkinClass($params)); +// } catch (\Exception $e) { +// \Log::debug($e); +// } +// +// } +// +// // Send to the admin, if settings dictate +// $recipient = new \App\Models\Recipients\AdminRecipient(); +// +// if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) { +// try { +// $recipient->notify(new static::$checkinClass($params)); +// } catch (\Exception $e) { +// \Log::debug($e); +// } +// +// } return $log; } diff --git a/app/Models/Manufacturer.php b/app/Models/Manufacturer.php index 81dbfdac8b..00ac8e7608 100755 --- a/app/Models/Manufacturer.php +++ b/app/Models/Manufacturer.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Facades\Gate; use Watson\Validating\ValidatingTrait; class Manufacturer extends SnipeModel @@ -49,26 +50,29 @@ class Manufacturer extends SnipeModel ]; use Searchable; - + /** * The attributes that should be included when searching the model. - * + * * @var array */ protected $searchableAttributes = ['name', 'created_at']; /** * The relations and their attributes that should be included when searching the model. - * + * * @var array */ - protected $searchableRelations = []; + protected $searchableRelations = []; - - public function has_models() + public function isDeletable() { - return $this->hasMany('\App\Models\AssetModel', 'manufacturer_id')->count(); + return (Gate::allows('delete', $this) + && ($this->assets()->count() === 0) + && ($this->licenses()->count() === 0) + && ($this->consumables()->count() === 0) + && ($this->accessories()->count() === 0)); } public function assets() diff --git a/app/Models/PredefinedKit.php b/app/Models/PredefinedKit.php new file mode 100644 index 0000000000..317cf3cd6a --- /dev/null +++ b/app/Models/PredefinedKit.php @@ -0,0 +1,183 @@ +] + * @version v1.0 + */ +class PredefinedKit extends SnipeModel +{ + protected $presenter = 'App\Presenters\PredefinedKitPresenter'; + use Presentable; + protected $table = 'kits'; + + /** + * Category validation rules + */ + public $rules = array( + 'name' => 'required|min:1|max:255|unique' + ); + + use ValidatingTrait; + + public $modelRules = [ + 'model_id' => 'required|exists:models,id', + 'quantity' => 'required|integer|min:1', + 'pivot_id' => 'integer|exists:kits_models,id' + ]; + + /** + * this rules use in edit an attached asset model form + * see PredefinedKit::_makeRuleHelper function for details + * @param int $model_id + * @param bool $new = true if append a new element to kit + */ + public function makeModelRules($model_id, $new=false) + { + return $this->_makeRuleHelper('models', 'kits_models', 'model_id', $model_id, $new); + } + + /** + * this rules use in edit an attached license form + * see PredefinedKit::_makeRuleHelper function for details + * @param int $license_id + * @param bool $new = true if append a new element to kit + */ + public function makeLicenseRules($license_id, $new=false) + { + return $this->_makeRuleHelper('licenses', 'kits_licenses', 'license_id', $license_id, $new); + } + + /** + * this rules use in edit an attached accessory form + * see PredefinedKit::_makeRuleHelper function for details + * @param int $accessoriy_id + * @param bool $new = true if append a new element to kit + */ + public function makeAccessoryRules($accessory_id, $new=false) + { + return $this->_makeRuleHelper('accessories', 'kits_accessories', 'accessory_id', $accessory_id, $new); + } + + /** + * this rules use in edit an attached consumable form + * see PredefinedKit::_makeRuleHelper function for details + * @param int $consumable_id + * @param bool $new = true if append a new element to kit + */ + public function makeConsumableRules($consumable_id, $new=false) + { + return $this->_makeRuleHelper('consumables', 'kits_consumables', 'consumable_id', $consumable_id, $new); + } + + /** + * Make rules for validation kit attached elements via Illuminate\Validation\Rule + * checks: + * uniqueness of the record in table for this kit + * existence of record in table + * and simple types check + * @param string $table element table name + * @param string $pivot_table kit+element table name + * @param string $pivot_elem_key element key name inside pivot table + * @param int $element_id + * @param bool $new = true if append a new element to kit + * @return array + */ + protected function _makeRuleHelper($table, $pivot_table, $pivot_elem_key, $element_id, $new) + { + $rule = [ + $pivot_elem_key => [ + 'required', + "exists:$table,id", + Rule::unique($pivot_table)->whereNot($pivot_elem_key, $element_id)->where('kit_id', $this->id) + ], + 'quantity' => 'required|integer|min:1' + ]; + if (!$new) { + $rule['pivot_id'] = "integer|exists:$pivot_table,id"; + + } + return $rule; + } + + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'name' + ]; + + use Searchable; + + /** + * The attributes that should be included when searching the kit. + * + * @var array + */ + protected $searchableAttributes = ['name']; + + /** + * The relations and their attributes that should be included when searching the kit. + * + * @var array + */ + protected $searchableRelations = []; + + + /** + * Establishes the kits -> models relationship + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function models() + { + return $this->belongsToMany('\App\Models\AssetModel', 'kits_models', 'kit_id', 'model_id')->withPivot('id', 'quantity'); + } + + public function assets() + { + return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'country_id', 'user_id'); + } + + /** + * Establishes the kits -> licenses relationship + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function licenses() + { + return $this->belongsToMany('\App\Models\License', 'kits_licenses', 'kit_id', 'license_id')->withPivot('id', 'quantity'); + } + + /** + * Establishes the kits -> licenses relationship + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function consumables() + { + return $this->belongsToMany('\App\Models\Consumable', 'kits_consumables', 'kit_id', 'consumable_id')->withPivot('id', 'quantity'); + } + + /** + * Establishes the kits -> licenses relationship + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function accessories() + { + return $this->belongsToMany('\App\Models\Accessory', 'kits_accessories', 'kit_id', 'accessory_id')->withPivot('id', 'quantity'); + } + + /** + * ----------------------------------------------- + * BEGIN QUERY SCOPES + * ----------------------------------------------- + **/ + +} diff --git a/app/Models/Recipients/AlertRecipient.php b/app/Models/Recipients/AlertRecipient.php index 548d39d752..07557649c9 100644 --- a/app/Models/Recipients/AlertRecipient.php +++ b/app/Models/Recipients/AlertRecipient.php @@ -1,13 +1,11 @@ email = trim($email); } - } diff --git a/app/Models/Recipients/Recipient.php b/app/Models/Recipients/Recipient.php index 888dd8e611..d04fd1f116 100644 --- a/app/Models/Recipients/Recipient.php +++ b/app/Models/Recipients/Recipient.php @@ -1,12 +1,12 @@ requests diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 4212b16185..f142bcca2b 100755 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -1,129 +1,214 @@ 'required|min:1|numeric', - 'qr_text' => 'max:31|nullable', - 'logo_img' => 'mimes:jpeg,bmp,png,gif', - 'alert_email' => 'email_array|nullable', - 'admin_cc_email' => 'email|nullable', - 'default_currency' => 'required', - 'locale' => 'required', - 'labels_per_page' => 'numeric|min:1', - 'labels_width' => 'numeric', - 'labels_height' => 'numeric', - 'labels_pmargin_left' => 'numeric|nullable', - 'labels_pmargin_right' => 'numeric|nullable', - 'labels_pmargin_top' => 'numeric|nullable', - 'labels_pmargin_bottom' => 'numeric|nullable', - 'labels_display_bgutter' => 'numeric|nullable', - 'labels_display_sgutter' => 'numeric|nullable', - 'labels_fontsize' => 'numeric|min:5', - 'labels_pagewidth' => 'numeric|nullable', - 'labels_pageheight' => 'numeric|nullable', - 'login_remote_user_enabled' => 'numeric|nullable', - 'login_common_disabled' => 'numeric|nullable', + 'brand' => 'required|min:1|numeric', + 'qr_text' => 'max:31|nullable', + 'logo_img' => 'mimes:jpeg,bmp,png,gif', + 'alert_email' => 'email_array|nullable', + 'admin_cc_email' => 'email|nullable', + 'default_currency' => 'required', + 'locale' => 'required', + 'slack_endpoint' => 'url|required_with:slack_channel|nullable', + 'labels_per_page' => 'numeric', + 'slack_channel' => 'regex:/^[\#\@]?\w+/|required_with:slack_endpoint|nullable', + 'slack_botname' => 'string|nullable', + 'labels_per_page' => 'numeric', + 'labels_width' => 'numeric', + 'labels_height' => 'numeric', + 'labels_pmargin_left' => 'numeric|nullable', + 'labels_pmargin_right' => 'numeric|nullable', + 'labels_pmargin_top' => 'numeric|nullable', + 'labels_pmargin_bottom' => 'numeric|nullable', + 'labels_display_bgutter' => 'numeric|nullable', + 'labels_display_sgutter' => 'numeric|nullable', + 'labels_fontsize' => 'numeric|min:5', + 'labels_pagewidth' => 'numeric|nullable', + 'labels_pageheight' => 'numeric|nullable', + 'login_remote_user_enabled' => 'numeric|nullable', + 'login_common_disabled' => 'numeric|nullable', 'login_remote_user_custom_logout_url' => 'string|nullable', - 'thumbnail_max_h' => 'numeric|max:500|min:25', - 'pwd_secure_min' => 'numeric|required|min:5', - 'audit_warning_days' => 'numeric|nullable', - 'audit_interval' => 'numeric|nullable', - 'custom_forgot_pass_url' => 'url|nullable', - 'privacy_policy_link' => 'nullable|url' + 'login_remote_user_header_name' => 'string|nullable', + 'thumbnail_max_h' => 'numeric|max:500|min:25', + 'pwd_secure_min' => 'numeric|required|min:5', + 'audit_warning_days' => 'numeric|nullable', + 'audit_interval' => 'numeric|nullable', + 'custom_forgot_pass_url' => 'url|nullable', + 'privacy_policy_link' => 'nullable|url', ]; - protected $fillable = ['site_name','email_domain','email_format','username_format']; + protected $fillable = [ + 'site_name', + 'email_domain', + 'email_format', + 'username_format', + ]; - public static function getSettings() + /** + * Get the app settings. + * Cache is expired on Setting model saved in EventServiceProvider. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return \App\Models\Setting|null + */ + public static function getSettings(): ?Setting { - static $static_cache = null; - - if (!$static_cache) { - if (Schema::hasTable('settings')) { - $static_cache = Setting::first(); + return Cache::rememberForever(self::APP_SETTINGS_KEY, function () { + // Need for setup as no tables exist + try { + return self::first(); + } catch (\Throwable $th) { + return null; } + }); } - return $static_cache; - - } - - public static function setupCompleted() + /** + * Check to see if setup process is complete. + * Cache is expired on Setting model saved in EventServiceProvider. + * + * @return bool + */ + public static function setupCompleted(): bool { + return Cache::rememberForever(self::SETUP_CHECK_KEY, function () { + try { + $usercount = User::withTrashed()->count(); + $settingsCount = self::count(); - $users_table_exists = Schema::hasTable('users'); - $settings_table_exists = Schema::hasTable('settings'); - - if ($users_table_exists && $settings_table_exists) { - $usercount = User::withTrashed()->count(); - $settingsCount = Setting::count(); - return ($usercount > 0 && $settingsCount > 0); + return $usercount > 0 && $settingsCount > 0; + } catch (\Throwable $th) { + // Catche the error if the tables dont exit } + return false; + }); } - public function lar_ver() + /** + * Get the current Laravel version. + * + * @return string + */ + public function lar_ver(): string { - $app = \App::getFacadeApplication(); + $app = App::getFacadeApplication(); + return $app::VERSION; } - public static function getDefaultEula() + /** + * Get the default EULA text. + * + * @return string|null + */ + public static function getDefaultEula(): ?string { - $Parsedown = new \Parsedown(); - if (Setting::getSettings()->default_eula_text) { - return $Parsedown->text(e(Setting::getSettings()->default_eula_text)); + if (self::getSettings()->default_eula_text) { + $parsedown = new Parsedown(); + + return $parsedown->text(e(self::getSettings()->default_eula_text)); } + return null; } - public function modellistCheckedValue ($element) { - + /** + * Check wether to show in model dropdowns. + * + * @param string $element + * + * @return bool + */ + public function modellistCheckedValue($element): bool + { + $settings = self::getSettings(); // If the value is blank for some reason - if ($this->modellist_displays=='') { + if ($settings->modellist_displays == '') { return false; } - $values = explode(',', $this->modellist_displays); + + $values = explode(',', $settings->modellist_displays); foreach ($values as $value) { if ($value == $element) { return true; } } - return false; + return false; } /** * Escapes the custom CSS, and then un-escapes the greater-than symbol * so it can work with direct descendant characters for bootstrap - * menu overrides like: + * menu overrides like:. * * .skin-blue .sidebar-menu>li.active>a, .skin-blue .sidebar-menu>li:hover>a * * Important: Do not remove the e() escaping here, as we output raw in the blade. * * @return string escaped CSS + * * @author A. Gianotto */ - public function show_custom_css() + public function show_custom_css(): string { - $custom_css = Setting::getSettings()->custom_css; + $custom_css = self::getSettings()->custom_css; $custom_css = e($custom_css); // Needed for modifying the bootstrap nav :( $custom_css = str_ireplace('script', 'SCRIPTS-NOT-ALLOWED-HERE', $custom_css); $custom_css = str_replace('>', '>', $custom_css); + // Allow String output (needs quotes) + $custom_css = str_replace('"', '"', $custom_css); + return $custom_css; } @@ -131,68 +216,82 @@ class Setting extends Model * Converts bytes into human readable file size. * * @param string $bytes + * * @return string human readable file size (2,87 Мб) + * * @author Mogilev Arseny */ - public static function fileSizeConvert($bytes) + public static function fileSizeConvert($bytes): string { $bytes = floatval($bytes); - $arBytes = array( - 0 => array( - "UNIT" => "TB", - "VALUE" => pow(1024, 4) - ), - 1 => array( - "UNIT" => "GB", - "VALUE" => pow(1024, 3) - ), - 2 => array( - "UNIT" => "MB", - "VALUE" => pow(1024, 2) - ), - 3 => array( - "UNIT" => "KB", - "VALUE" => 1024 - ), - 4 => array( - "UNIT" => "B", - "VALUE" => 1 - ), - ); + $arBytes = [ + 0 => [ + 'UNIT' => 'TB', + 'VALUE' => pow(1024, 4), + ], + 1 => [ + 'UNIT' => 'GB', + 'VALUE' => pow(1024, 3), + ], + 2 => [ + 'UNIT' => 'MB', + 'VALUE' => pow(1024, 2), + ], + 3 => [ + 'UNIT' => 'KB', + 'VALUE' => 1024, + ], + 4 => [ + 'UNIT' => 'B', + 'VALUE' => 1, + ], + ]; foreach ($arBytes as $arItem) { - if ($bytes >= $arItem["VALUE"]) { - $result = $bytes / $arItem["VALUE"]; - $result = round($result, 2) .$arItem["UNIT"]; + if ($bytes >= $arItem['VALUE']) { + $result = $bytes / $arItem['VALUE']; + $result = round($result, 2).$arItem['UNIT']; break; } } + return $result; } /** * The url for slack notifications. - * Used by Notifiable trait. - * @return mixed + * Used by Notifiable trait. + * + * @return string */ - public function routeNotificationForSlack() + public function routeNotificationForSlack(): string { // At this point the endpoint is the same for everything. // In the future this may want to be adapted for individual notifications. - return $this->slack_endpoint; + return self::getSettings()->slack_endpoint; } - public function routeNotificationForMail() + /** + * Get the mail reply to address from configuration. + * + * @return string + */ + public function routeNotificationForMail(): string { // At this point the endpoint is the same for everything. // In the future this may want to be adapted for individual notifications. return config('mail.reply_to.address'); } - public static function passwordComplexityRulesSaving($action = 'update') + /** + * Get the password complexity rule. + * + * @return string + */ + public static function passwordComplexityRulesSaving($action = 'update'): string { $security_rules = ''; - $settings = Setting::getSettings(); + $settings = self::getSettings(); // Check if they have uncommon password enforcement selected in settings if ($settings->pwd_secure_uncommon == 1) { @@ -200,8 +299,8 @@ class Setting extends Model } // Check for any secure password complexity rules that may have been selected - if ($settings->pwd_secure_complexity!='') { - $security_rules .= '|'.$settings->pwd_secure_complexity; + if ($settings->pwd_secure_complexity != '') { + $security_rules .= '|'.$settings->pwd_secure_complexity; } if ($action == 'update') { @@ -209,9 +308,44 @@ class Setting extends Model } return 'required|min:'.$settings->pwd_secure_min.$security_rules; - } + /** + * Get the specific LDAP settings + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return Collection + */ + public static function getLdapSettings(): Collection + { + $ldapSettings = self::select([ + 'ldap_enabled', + 'ldap_server', + 'ldap_uname', + 'ldap_pword', + 'ldap_basedn', + 'ldap_filter', + 'ldap_username_field', + 'ldap_lname_field', + 'ldap_fname_field', + 'ldap_auth_filter_query', + 'ldap_version', + 'ldap_active_flag', + 'ldap_emp_num', + 'ldap_email', + 'ldap_server_cert_ignore', + 'ldap_port', + 'ldap_tls', + 'ldap_pw_sync', + 'is_ad', + 'ad_domain', + 'ad_append_domain', + ])->first()->getAttributes(); + return collect($ldapSettings); + } } diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index f5505a74a8..2911be1c38 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -3,7 +3,6 @@ namespace App\Models; use App\Helpers\Helper; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; class SnipeModel extends Model diff --git a/app/Models/Statuslabel.php b/app/Models/Statuslabel.php index fa6f6df1ba..cd4672b841 100755 --- a/app/Models/Statuslabel.php +++ b/app/Models/Statuslabel.php @@ -2,9 +2,7 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; -use App\Models\SnipeModel; use App\Models\Traits\Searchable; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; @@ -50,19 +48,28 @@ class Statuslabel extends SnipeModel * * @var array */ - protected $searchableRelations = []; + protected $searchableRelations = []; /** - * Get assets with associated status label + * Establishes the status label -> assets relationship * - * @return \Illuminate\Support\Collection + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assets() { return $this->hasMany('\App\Models\Asset', 'status_id'); } + /** + * Gets the status label type + * + * @author A. Gianotto + * @since [v1.0] + * @return string + */ public function getStatuslabelType() { @@ -78,6 +85,11 @@ class Statuslabel extends SnipeModel } + /** + * Query builder scope to for pending status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopePending() { return $this->where('pending', '=', 1) @@ -85,6 +97,11 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 0); } + /** + * Query builder scope for archived status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeArchived() { return $this->where('pending', '=', 0) @@ -92,6 +109,11 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 0); } + /** + * Query builder scope for deployable status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeDeployable() { return $this->where('pending', '=', 0) @@ -99,7 +121,13 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 1); } - + /** + * Helper function to determine type attributes + * + * @author A. Gianotto + * @since [v1.0] + * @return string + */ public static function getStatuslabelTypesForDB($type) { diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php index 82c3a0770c..230a713cda 100755 --- a/app/Models/Supplier.php +++ b/app/Models/Supplier.php @@ -2,9 +2,7 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; -use App\Models\SnipeModel; use App\Models\Traits\Searchable; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; @@ -66,13 +64,30 @@ class Supplier extends SnipeModel protected $fillable = ['name','address','address2','city','state','country','zip','phone','fax','email','contact','url','notes']; - // Eager load counts. - // We do this to eager load the "count" of seats from the controller. Otherwise calling "count()" on each model results in n+1 + /** + * Eager load counts + * + * We do this to eager load the "count" of seats from the controller. + * Otherwise calling "count()" on each model results in n+1. + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetsRelation() { return $this->hasMany(Asset::class)->whereNull('deleted_at')->selectRaw('supplier_id, count(*) as count')->groupBy('supplier_id'); } + /** + * Sets the license seat count attribute + * + * @todo I don't see the licenseSeatsRelation here? + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function getLicenseSeatsCountAttribute() { if ($this->licenseSeatsRelation->first()) { @@ -81,21 +96,50 @@ class Supplier extends SnipeModel return 0; } + + /** + * Establishes the supplier -> assets relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasMany('\App\Models\Asset', 'supplier_id'); } + /** + * Establishes the supplier -> accessories relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function accessories() { return $this->hasMany('\App\Models\Accessory', 'supplier_id'); } + /** + * Establishes the supplier -> asset maintenances relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function asset_maintenances() { return $this->hasMany('\App\Models\AssetMaintenance', 'supplier_id'); } + /** + * Return the number of assets by supplier + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function num_assets() { if ($this->assetsRelation->first()) { @@ -105,16 +149,39 @@ class Supplier extends SnipeModel return 0; } + /** + * Establishes the supplier -> license relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->hasMany('\App\Models\License', 'supplier_id'); } + /** + * Return the number of licenses by supplier + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function num_licenses() { return $this->licenses()->count(); } + /** + * Add http to the url in suppliers if the user didn't give one + * + * @todo this should be handled via validation, no? + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function addhttp($url) { if (!preg_match("~^(?:f|ht)tps?://~i", $url)) { diff --git a/app/Models/Throttle.php b/app/Models/Throttle.php deleted file mode 100644 index 85e447378e..0000000000 --- a/app/Models/Throttle.php +++ /dev/null @@ -1,14 +0,0 @@ -belongsTo('User', 'user_id'); - } -} diff --git a/app/Models/Traits/Acceptable.php b/app/Models/Traits/Acceptable.php new file mode 100644 index 0000000000..4da3575182 --- /dev/null +++ b/app/Models/Traits/Acceptable.php @@ -0,0 +1,28 @@ + + */ +trait Acceptable { + /** + * Run after the checkout acceptance was accepted by the user + * + * @param User $acceptedBy + * @param string $signature + */ + public function acceptedCheckout(User $acceptedBy, $signature) {} + + /** + * Run after the checkout acceptance was declined by the user + * + * @param User $acceptedBy + * @param string $signature + */ + public function declinedCheckout(User $declinedBy, $signature) {} +} diff --git a/app/Models/Traits/Searchable.php b/app/Models/Traits/Searchable.php index 96e88f7cb5..e43081e557 100644 --- a/app/Models/Traits/Searchable.php +++ b/app/Models/Traits/Searchable.php @@ -17,9 +17,9 @@ trait Searchable { /** * Performs a search on the model, using the provided search terms * - * @param Illuminate\Database\Eloquent\Builder $query The query to start the search on + * @param \Illuminate\Database\Eloquent\Builder $query The query to start the search on * @param string $search - * @return Illuminate\Database\Eloquent\Builder A query with added "where" clauses + * @return \Illuminate\Database\Eloquent\Builder A query with added "where" clauses */ public function scopeTextSearch($query, $search) { diff --git a/app/Models/User.php b/app/Models/User.php index f163ba217c..ff886905fc 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,23 +1,24 @@ 'boolean', + 'activated' => 'boolean', + 'manager_id' => 'integer', + 'location_id' => 'integer', + 'company_id' => 'integer', ]; /** @@ -67,9 +71,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo 'first_name' => 'required|string|min:1', 'username' => 'required|string|min:1|unique_undeleted', 'email' => 'email|nullable', - 'password' => 'required|min:6', + 'password' => 'required|min:8', 'locale' => 'max:10|nullable', - 'website' => 'url|nullable', + 'website' => 'url|nullable', + 'manager_id' => 'nullable|exists:users,id|different:users.id', + 'location_id' => 'exists:locations,id|nullable', ]; use Searchable; @@ -99,9 +105,20 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo 'userloc' => ['name'], 'department' => ['name'], 'groups' => ['name'], + 'company' => ['name'], 'manager' => ['first_name', 'last_name', 'username'] ]; + /** + * Check user permissions + * + * Parses the user and group permission masks to see if the user + * is authorized to do the thing + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ public function hasAccess($section) { if ($this->isSuperUser()) { @@ -116,12 +133,13 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo $user_permissions = json_decode($this->permissions, true); + $is_user_section_permissions_set = ($user_permissions != '') && array_key_exists($section, $user_permissions); //If the user is explicitly granted, return true - if (($user_permissions!='') && ((array_key_exists($section, $user_permissions)) && ($user_permissions[$section]=='1'))) { + if ($is_user_section_permissions_set && ($user_permissions[$section]=='1')) { return true; } // If the user is explicitly denied, return false - if (($user_permissions=='') || array_key_exists($section, $user_permissions) && ($user_permissions[$section]=='-1')) { + if ($is_user_section_permissions_set && ($user_permissions[$section]=='-1')) { return false; } @@ -136,6 +154,13 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo return false; } + /** + * Checks if the user is a SuperUser + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ public function isSuperUser() { if (!$user_permissions = json_decode($this->permissions, true)) { @@ -158,21 +183,63 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } + /** + * Establishes the user -> company relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the user -> department relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function department() { return $this->belongsTo('\App\Models\Department', 'department_id'); } + /** + * Checks activated status + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ + public function isActivated() + { + return $this->activated ==1; + } + + /** + * Returns the full name attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return string + */ public function getFullNameAttribute() { return $this->first_name . " " . $this->last_name; } + /** + * Returns the complete name attribute with username + * + * @todo refactor this so it's less repetitive and dumb + * + * @author A. Gianotto + * @since [v2.0] + * @return string + */ public function getCompleteNameAttribute() { return $this->last_name . ", " . $this->first_name . " (" . $this->username . ")"; @@ -193,7 +260,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo /** - * Get assets assigned to this user + * Establishes the user -> assets relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assets() { @@ -201,7 +272,14 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Get assets assigned to this user + * Establishes the user -> maintenances relationship + * + * This would only be used to return maintenances that this user + * created. + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assetmaintenances() { @@ -209,7 +287,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Get accessories assigned to this user + * Establishes the user -> accessories relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function accessories() { @@ -217,7 +299,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Get consumables assigned to this user + * Establishes the user -> consumables relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function consumables() { @@ -225,7 +311,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Get licenses assigned to this user + * Establishes the user -> license seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function licenses() { @@ -233,78 +323,104 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Get action logs for this user + * Establishes the user -> actionlogs relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function userlog() { return $this->hasMany('\App\Models\Actionlog', 'target_id')->where('target_type', '=', 'App\Models\User')->orderBy('created_at', 'DESC')->withTrashed(); } + /** + * Establishes the user -> location relationship + * * Get the asset's location based on the assigned user - * @todo - this should be removed once we're sure we've switched it - * to location() - **/ + * + * @todo - this should be removed once we're sure we've switched it to location() + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function userloc() { return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed(); } + /** - * Get the asset's location based on the assigned user - **/ + * Establishes the user -> location relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed(); } /** - * Get the user's manager based on the assigned user - **/ + * Establishes the user -> manager relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manager() { return $this->belongsTo('\App\Models\User', 'manager_id')->withTrashed(); } /** - * Get any locations the user manages. - **/ + * Establishes the user -> managed locations relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function managedLocations() { return $this->hasMany('\App\Models\Location', 'manager_id'); } /** - * Get user groups + * Establishes the user -> groups relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function groups() { return $this->belongsToMany('\App\Models\Group', 'users_groups'); } - - public function accountStatus() - { - if ($this->throttle) { - if ($this->throttle->suspended==1) { - return 'suspended'; - } elseif ($this->throttle->banned==1) { - return 'banned'; - } else { - return false; - } - } else { - return false; - } - } - + /** + * Establishes the user -> assets relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Asset', 'id')->withTrashed(); } /** - * Get uploads for this asset + * Establishes the user -> uploads relationship + * + * @todo I don't think we use this? + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function uploads() { @@ -316,28 +432,42 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } /** - * Fetch Items User has requested + * Establishes the user -> requested assets relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkoutRequests() { return $this->belongsToMany(Asset::class, 'checkout_requests', 'user_id', 'requestable_id')->whereNull('canceled_at'); } - public function throttle() - { - return $this->hasOne('\App\Models\Throttle'); - } - - public function scopeGetDeleted($query) - { - return $query->withTrashed()->whereNotNull('users.deleted_at'); - } + /** + * Query builder scope to return NOT-deleted users + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @return \Illuminate\Database\Query\Builder + */ public function scopeGetNotDeleted($query) { return $query->whereNull('deleted_at'); } + /** + * Query builder scope to return users by email or username + * + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @param string $user_username + * @param string $user_email + * @return \Illuminate\Database\Query\Builder + */ public function scopeMatchEmailOrUsername($query, $user_username, $user_email) { return $query->where('email', '=', $user_email) @@ -345,13 +475,22 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo ->orWhere('username', '=', $user_email); } + /** + * Generate email from full name + * + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @return string + */ public static function generateEmailFromFullName($name) { - $username = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $name); + $username = User::generateFormattedNameFromFullName($name, Setting::getSettings()->email_format); return $username['username'].'@'.Setting::getSettings()->email_domain; } - public static function generateFormattedNameFromFullName($format = 'filastname', $users_name) + public static function generateFormattedNameFromFullName($users_name, $format = 'filastname') { // If there was only one name given @@ -373,6 +512,9 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo } elseif ($format=='lastnamefirstinitial') { $username = str_slug($last_name.substr($first_name, 0, 1)); + } elseif ($format=='firstintial.lastname') { + $username = substr($first_name, 0, 1).'.'.str_slug($last_name); + } elseif ($format=='firstname_lastname') { $username = str_slug($first_name).'_'.str_slug($last_name); @@ -487,9 +629,9 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo /** * Run additional, advanced searches. * - * @param Illuminate\Database\Eloquent\Builder $query - * @param array $term The search terms - * @return Illuminate\Database\Eloquent\Builder + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param array $terms The search terms + * @return \Illuminate\Database\Eloquent\Builder */ public function advancedTextSearch(Builder $query, array $terms) { @@ -500,34 +642,27 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo return $query; } - + /** + * Query builder scope to return users by group + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param int $id + * @return \Illuminate\Database\Query\Builder + */ public function scopeByGroup($query, $id) { return $query->whereHas('groups', function ($query) use ($id) { $query->where('permission_groups.id', '=', $id); }); } - /** - * Query builder scope for Deleted users - * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * - * @return Illuminate\Database\Query\Builder Modified query builder - */ - - public function scopeDeleted($query) - { - return $query->whereNotNull('users.deleted_at'); - } - /** * Query builder scope to order on manager * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManager($query, $order) { @@ -538,10 +673,10 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -552,10 +687,10 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo /** * Query builder scope to order on department * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderDepartment($query, $order) { @@ -574,4 +709,10 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo { return $query->leftJoin('companies as companies_user', 'users.company_id', '=', 'companies_user.id')->orderBy('companies_user.name', $order); } + + public function preferredLocale(){ + return $this->locale; + } + + } diff --git a/app/Notifications/AuditNotification.php b/app/Notifications/AuditNotification.php index 20d3b4a090..900650e975 100644 --- a/app/Notifications/AuditNotification.php +++ b/app/Notifications/AuditNotification.php @@ -6,7 +6,6 @@ use App\Models\Setting; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Notifications\Messages\MailMessage; class AuditNotification extends Notification { @@ -30,10 +29,9 @@ class AuditNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; if (Setting::getSettings()->slack_endpoint) { @@ -43,13 +41,13 @@ class AuditNotification extends Notification return $notifyBy; } - public function toSlack($notifiable) + public function toSlack() { return (new SlackMessage) ->success() ->content(class_basename(get_class($this->params['item'])) . " Audited") - ->attachment(function ($attachment) use ($notifiable) { + ->attachment(function ($attachment) { $item = $this->params['item']; $admin_user = $this->params['admin']; $fields = [ @@ -62,27 +60,4 @@ class AuditNotification extends Notification ->fields($fields); }); } - /** - * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage - */ - public function toMail($notifiable) - { - - } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CheckinAccessoryNotification.php b/app/Notifications/CheckinAccessoryNotification.php index 052279892e..cc712e271d 100644 --- a/app/Notifications/CheckinAccessoryNotification.php +++ b/app/Notifications/CheckinAccessoryNotification.php @@ -2,71 +2,97 @@ namespace App\Notifications; +use App\Models\Accessory; use App\Models\Setting; -use App\Models\SnipeModel; use App\Models\User; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; class CheckinAccessoryNotification extends Notification { use Queueable; - /** - * @var - */ - private $params; /** * Create a new notification instance. * * @param $params */ - public function __construct($params) + public function __construct(Accessory $accessory, $checkedOutTo, User $checkedInby, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->note = ''; - $this->target_type = $params['target']; - $this->settings = $params['settings']; - - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } - - - + $this->item = $accessory; + $this->target = $checkedOutTo; + $this->admin = $checkedInby; + $this->note = $note; + $this->settings = Setting::getSettings(); + \Log::debug('Constructor for notification fired'); } /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ public function via() { - + \Log::debug('via called'); $notifyBy = []; if (Setting::getSettings()->slack_endpoint) { $notifyBy[] = 'slack'; } - /** - * Only send checkin notifications to users if the category - * has the corresponding checkbox checked. - */ - if ($this->item->checkin_email() && $this->target instanceof User && $this->target->email != '') - { - \Log::debug('use email'); - $notifyBy[] = 'mail'; + if (Setting::getSettings()->slack_endpoint!='') { + $notifyBy[] = 'slack'; } + + /** + * Only send notifications to users that have email addresses + */ + if ($this->target instanceof User && $this->target->email != '') { + + \Log::debug('The target is a user'); + + /** + * Send an email if the asset requires acceptance, + * so the user can accept or decline the asset + */ + if (($this->item->requireAcceptance()) || ($this->item->getEula()) || ($this->item->checkin_email())) { + $notifyBy[] = 'mail'; + } + + + + + + /** + * Send an email if the asset requires acceptance, + * so the user can accept or decline the asset + */ + if ($this->item->requireAcceptance()) { + \Log::debug('This accessory requires acceptance'); + } + + /** + * Send an email if the item has a EULA, since the user should always receive it + */ + if ($this->item->getEula()) { + \Log::debug('This accessory has a EULA'); + } + + /** + * Send an email if an email should be sent at checkin/checkout + */ + if ($this->item->checkin_email()) { + \Log::debug('This accessory has a checkin_email()'); + } + + } + + \Log::debug('checkin_email on this category is '.$this->item->checkin_email()); + return $notifyBy; } @@ -79,14 +105,11 @@ class CheckinAccessoryNotification extends Notification $note = $this->note; $botname = ($this->settings->slack_botname) ? $this->settings->slack_botname : 'Snipe-Bot' ; - $fields = [ 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', 'By' => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', ]; - - return (new SlackMessage) ->content(':arrow_down: :keyboard: Accessory Checked In') ->from($botname) @@ -102,10 +125,9 @@ class CheckinAccessoryNotification extends Notification * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { - - + \Log::debug('to email called'); return (new MailMessage)->markdown('notifications.markdown.checkin-accessory', [ 'item' => $this->item, @@ -116,17 +138,4 @@ class CheckinAccessoryNotification extends Notification ->subject('Accessory checked in'); } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CheckinAssetNotification.php b/app/Notifications/CheckinAssetNotification.php index 78f3f00664..0b0c29d7b5 100644 --- a/app/Notifications/CheckinAssetNotification.php +++ b/app/Notifications/CheckinAssetNotification.php @@ -2,13 +2,13 @@ namespace App\Notifications; +use App\Models\Asset; use App\Models\Setting; -use Illuminate\Bus\Queueable; use App\Models\User; -use Illuminate\Notifications\Notification; -use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; +use Illuminate\Notifications\Notification; class CheckinAssetNotification extends Notification { @@ -20,19 +20,15 @@ class CheckinAssetNotification extends Notification * * @param $params */ - public function __construct($params) + public function __construct(Asset $asset, $checkedOutTo, User $checkedInBy, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->note = ''; - $this->expected_checkin = ''; - $this->target_type = $params['target_type']; - $this->settings = $params['settings']; + $this->target = $checkedOutTo; + $this->item = $asset; + $this->admin = $checkedInBy; + $this->note = $note; - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } + $this->settings = Setting::getSettings(); + $this->expected_checkin = ''; if ($this->item->expected_checkin) { $this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date', @@ -43,7 +39,6 @@ class CheckinAssetNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ public function via() @@ -57,7 +52,7 @@ class CheckinAssetNotification extends Notification } /** - * Only send checkin notifications to users if the category + * Only send checkin notifications to users if the category * has the corresponding checkbox checked. */ if ($this->item->checkin_email() && $this->target instanceof User && $this->target->email != '') @@ -82,7 +77,7 @@ class CheckinAssetNotification extends Notification trans('general.status') => $item->assetstatus->name, trans('general.location') => ($item->location) ? $item->location->name : '', ]; - + return (new SlackMessage) ->content(':arrow_down: :computer: Asset Checked In') ->from($botname) @@ -98,13 +93,10 @@ class CheckinAssetNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail() { - - $fields = []; // Check if the item has custom fields associated with it diff --git a/app/Notifications/CheckinLicenseNotification.php b/app/Notifications/CheckinLicenseSeatNotification.php similarity index 73% rename from app/Notifications/CheckinLicenseNotification.php rename to app/Notifications/CheckinLicenseSeatNotification.php index a0327f6faf..f9d4914c37 100644 --- a/app/Notifications/CheckinLicenseNotification.php +++ b/app/Notifications/CheckinLicenseSeatNotification.php @@ -2,17 +2,15 @@ namespace App\Notifications; +use App\Models\LicenseSeat; use App\Models\Setting; -use App\Models\SnipeModel; use App\Models\User; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; -class CheckinLicenseNotification extends Notification +class CheckinLicenseSeatNotification extends Notification { use Queueable; /** @@ -25,28 +23,21 @@ class CheckinLicenseNotification extends Notification * * @param $params */ - public function __construct($params) + public function __construct(LicenseSeat $licenseSeat, $checkedOutTo, User $checkedInBy, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->note = ''; - $this->settings = $params['settings']; - $this->target_type = $params['target_type']; - - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } - + $this->target = $checkedOutTo; + $this->item = $licenseSeat->license; + $this->admin = $checkedInBy; + $this->note = $note; + $this->settings = Setting::getSettings(); } /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; @@ -55,7 +46,7 @@ class CheckinLicenseNotification extends Notification } /** - * Only send checkin notifications to users if the category + * Only send checkin notifications to users if the category * has the corresponding checkbox checked. */ if ($this->item->checkin_email() && $this->target instanceof User && $this->target->email != '') @@ -66,7 +57,7 @@ class CheckinLicenseNotification extends Notification return $notifyBy; } - public function toSlack($notifiable) + public function toSlack() { $target = $this->target; @@ -106,9 +97,8 @@ class CheckinLicenseNotification extends Notification * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { - return (new MailMessage)->markdown('notifications.markdown.checkin-license', [ 'item' => $this->item, @@ -120,16 +110,4 @@ class CheckinLicenseNotification extends Notification } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CheckoutAccessoryNotification.php b/app/Notifications/CheckoutAccessoryNotification.php index 4e8950619d..2c2001253d 100644 --- a/app/Notifications/CheckoutAccessoryNotification.php +++ b/app/Notifications/CheckoutAccessoryNotification.php @@ -2,56 +2,40 @@ namespace App\Notifications; +use App\Models\Accessory; use App\Models\Setting; -use App\Models\SnipeModel; use App\Models\User; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; class CheckoutAccessoryNotification extends Notification { use Queueable; - /** - * @var - */ - private $params; /** * Create a new notification instance. - * - * @param $params */ - public function __construct($params) + public function __construct(Accessory $accessory, $checkedOutTo, User $checkedOutBy, $acceptance, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->log_id = $params['log_id']; - $this->note = ''; - $this->last_checkout = ''; - $this->expected_checkin = ''; - $this->target_type = $params['target_type']; - $this->settings = $params['settings']; - - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } + $this->item = $accessory; + $this->admin = $checkedOutBy; + $this->note = $note; + $this->target = $checkedOutTo; + $this->acceptance = $acceptance; + $this->settings = Setting::getSettings(); } /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; @@ -67,7 +51,7 @@ class CheckoutAccessoryNotification extends Notification if ($this->target instanceof User && $this->target->email != '') { /** - * Send an email if the asset requires acceptance, + * Send an email if the asset requires acceptance, * so the user can accept or decline the asset */ if ($this->item->requireAcceptance()) { @@ -86,17 +70,15 @@ class CheckoutAccessoryNotification extends Notification */ if ($this->item->checkin_email()) { $notifyBy[1] = 'mail'; - } + } } return $notifyBy; } - public function toSlack($notifiable) + public function toSlack() { - - $target = $this->target; $admin = $this->admin; $item = $this->item; @@ -108,8 +90,6 @@ class CheckoutAccessoryNotification extends Notification 'By' => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', ]; - - return (new SlackMessage) ->content(':arrow_up: :keyboard: Accessory Checked Out') ->from($botname) @@ -122,16 +102,16 @@ class CheckoutAccessoryNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { - \Log::debug($this->item->getImageUrl()); $eula = $this->item->getEula(); $req_accept = $this->item->requireAcceptance(); + $accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance); + return (new MailMessage)->markdown('notifications.markdown.checkout-accessory', [ 'item' => $this->item, @@ -140,22 +120,9 @@ class CheckoutAccessoryNotification extends Notification 'target' => $this->target, 'eula' => $eula, 'req_accept' => $req_accept, - 'accept_url' => url('/').'/account/accept-asset/'.$this->log_id, + 'accept_url' => $accept_url, ]) ->subject(trans('mail.Confirm_accessory_delivery')); } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CheckoutAssetNotification.php b/app/Notifications/CheckoutAssetNotification.php index 8451d6dcd9..ff759f68ef 100644 --- a/app/Notifications/CheckoutAssetNotification.php +++ b/app/Notifications/CheckoutAssetNotification.php @@ -2,42 +2,36 @@ namespace App\Notifications; +use App\Models\Asset; use App\Models\Setting; use App\Models\User; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Contracts\Queue\ShouldQueue; class CheckoutAssetNotification extends Notification { use Queueable; - /** - * @var - */ - private $params; /** * Create a new notification instance. * * @param $params */ - public function __construct($params) + public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->log_id = $params['log_id']; - $this->note = ''; + + $this->item = $asset; + $this->admin = $checkedOutBy; + $this->note = $note; + $this->target = $checkedOutTo; + $this->acceptance = $acceptance; + + $this->settings = Setting::getSettings(); + $this->last_checkout = ''; $this->expected_checkin = ''; - $this->target_type = $params['target_type']; - $this->settings = $params['settings']; - - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } if ($this->item->last_checkout) { $this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date', @@ -55,7 +49,6 @@ class CheckoutAssetNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ public function via() @@ -74,7 +67,7 @@ class CheckoutAssetNotification extends Notification if ($this->target instanceof User && $this->target->email != '') { /** - * Send an email if the asset requires acceptance, + * Send an email if the asset requires acceptance, * so the user can accept or decline the asset */ if ($this->item->requireAcceptance()) { @@ -86,14 +79,14 @@ class CheckoutAssetNotification extends Notification */ if ($this->item->getEula()) { $notifyBy[1] = 'mail'; - } + } /** * Send an email if an email should be sent at checkin/checkout */ if ($this->item->checkin_email()) { $notifyBy[1] = 'mail'; - } + } } @@ -146,17 +139,18 @@ class CheckoutAssetNotification extends Notification $fields = $this->item->model->fieldset->fields; } + $accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance); + $message = (new MailMessage)->markdown('notifications.markdown.checkout-asset', [ 'item' => $this->item, 'admin' => $this->admin, 'note' => $this->note, - 'log_id' => $this->note, 'target' => $this->target, 'fields' => $fields, 'eula' => $eula, 'req_accept' => $req_accept, - 'accept_url' => url('/').'/account/accept-asset/'.$this->log_id, + 'accept_url' => $accept_url, 'last_checkout' => $this->last_checkout, 'expected_checkin' => $this->expected_checkin, ]) @@ -165,7 +159,6 @@ class CheckoutAssetNotification extends Notification return $message; - } } diff --git a/app/Notifications/CheckoutConsumableNotification.php b/app/Notifications/CheckoutConsumableNotification.php index 1811c70401..edf970789d 100644 --- a/app/Notifications/CheckoutConsumableNotification.php +++ b/app/Notifications/CheckoutConsumableNotification.php @@ -2,15 +2,13 @@ namespace App\Notifications; +use App\Models\Consumable; use App\Models\Setting; -use App\Models\SnipeModel; use App\Models\User; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; class CheckoutConsumableNotification extends Notification { @@ -25,31 +23,25 @@ class CheckoutConsumableNotification extends Notification * * @param $params */ - public function __construct($params) + public function __construct(Consumable $consumable, $checkedOutTo, User $checkedOutBy, $acceptance, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->log_id = $params['log_id']; - $this->note = ''; - $this->last_checkout = ''; - $this->expected_checkin = ''; - $this->target_type = $params['target_type']; - $this->settings = $params['settings']; - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } + $this->item = $consumable; + $this->admin = $checkedOutBy; + $this->note = $note; + $this->target = $checkedOutTo; + $this->acceptance = $acceptance; + + $this->settings = Setting::getSettings(); } /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; @@ -63,7 +55,7 @@ class CheckoutConsumableNotification extends Notification if ($this->target instanceof User && $this->target->email != '') { /** - * Send an email if the asset requires acceptance, + * Send an email if the asset requires acceptance, * so the user can accept or decline the asset */ if ($this->item->requireAcceptance()) { @@ -75,21 +67,23 @@ class CheckoutConsumableNotification extends Notification */ if ($this->item->getEula()) { $notifyBy[1] = 'mail'; - } + } /** * Send an email if an email should be sent at checkin/checkout */ + if ((method_exists($this->item, 'checkin_email')) && ($this->item->checkin_email())) { + $notifyBy[1] = 'mail'; - } + } } return $notifyBy; } - public function toSlack($notifiable) + public function toSlack() { $target = $this->target; $admin = $this->admin; @@ -114,41 +108,29 @@ class CheckoutConsumableNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { \Log::debug($this->item->getImageUrl()); $eula = $this->item->getEula(); $req_accept = $this->item->requireAcceptance(); + $accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance); + return (new MailMessage)->markdown('notifications.markdown.checkout-consumable', [ 'item' => $this->item, 'admin' => $this->admin, 'note' => $this->note, - 'log_id' => $this->note, 'target' => $this->target, 'eula' => $eula, 'req_accept' => $req_accept, - 'accept_url' => url('/').'/account/accept-asset/'.$this->log_id, + 'accept_url' => $accept_url, ]) ->subject(trans('mail.Confirm_consumable_delivery')); } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CheckoutLicenseNotification.php b/app/Notifications/CheckoutLicenseSeatNotification.php similarity index 71% rename from app/Notifications/CheckoutLicenseNotification.php rename to app/Notifications/CheckoutLicenseSeatNotification.php index 93530e2cde..3ec2c1f9ae 100644 --- a/app/Notifications/CheckoutLicenseNotification.php +++ b/app/Notifications/CheckoutLicenseSeatNotification.php @@ -2,17 +2,15 @@ namespace App\Notifications; +use App\Models\LicenseSeat; use App\Models\Setting; -use App\Models\SnipeModel; use App\Models\User; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; -class CheckoutLicenseNotification extends Notification +class CheckoutLicenseSeatNotification extends Notification { use Queueable; /** @@ -25,29 +23,20 @@ class CheckoutLicenseNotification extends Notification * * @param $params */ - public function __construct($params) + public function __construct(LicenseSeat $licenseSeat, $checkedOutTo, User $checkedOutBy, $acceptance, $note) { - $this->target = $params['target']; - $this->item = $params['item']; - $this->admin = $params['admin']; - $this->log_id = $params['log_id']; - $this->note = ''; - $this->target_type = $params['target_type']; - $this->settings = $params['settings']; - $this->target_type = $params['target_type']; - - if (array_key_exists('note', $params)) { - $this->note = $params['note']; - } - - + $this->item = $licenseSeat->license; + $this->admin = $checkedOutBy; + $this->note = $note; + $this->target = $checkedOutTo; + $this->acceptance = $acceptance; + $this->settings = Setting::getSettings(); } /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ public function via() @@ -64,7 +53,7 @@ class CheckoutLicenseNotification extends Notification if ($this->target instanceof User && $this->target->email != '') { /** - * Send an email if the asset requires acceptance, + * Send an email if the asset requires acceptance, * so the user can accept or decline the asset */ if ($this->item->requireAcceptance()) { @@ -76,23 +65,22 @@ class CheckoutLicenseNotification extends Notification */ if ($this->item->getEula()) { $notifyBy[1] = 'mail'; - } + } /** * Send an email if an email should be sent at checkin/checkout */ if ($this->item->checkin_email()) { $notifyBy[1] = 'mail'; - } + } } - + return $notifyBy; } - public function toSlack($notifiable) + public function toSlack() { - $target = $this->target; $admin = $this->admin; $item = $this->item; @@ -116,15 +104,16 @@ class CheckoutLicenseNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { $eula = method_exists($this->item, 'getEula') ? $this->item->getEula() : ''; $req_accept = method_exists($this->item, 'requireAcceptance') ? $this->item->requireAcceptance() : 0; + $accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance); + return (new MailMessage)->markdown('notifications.markdown.checkout-license', [ 'item' => $this->item, @@ -133,22 +122,10 @@ class CheckoutLicenseNotification extends Notification 'target' => $this->target, 'eula' => $eula, 'req_accept' => $req_accept, - 'accept_url' => url('/').'/account/accept-asset/'.$this->log_id, + 'accept_url' => $accept_url, ]) ->subject(trans('mail.Confirm_license_delivery')); } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/CurrentInventory.php b/app/Notifications/CurrentInventory.php new file mode 100644 index 0000000000..d0161aa165 --- /dev/null +++ b/app/Notifications/CurrentInventory.php @@ -0,0 +1,51 @@ +user = $user; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via() + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail() + { + $message = (new MailMessage)->markdown('notifications.markdown.user-inventory', + [ + 'assets' => $this->user->assets, + 'accessories' => $this->user->accessories, + 'licenses' => $this->user->licenses, + ]) + ->subject('Inventory Report'); + + return $message; + } +} diff --git a/app/Notifications/ExpectedCheckinAdminNotification.php b/app/Notifications/ExpectedCheckinAdminNotification.php index 6dd481ea1f..c90c2fa3e1 100644 --- a/app/Notifications/ExpectedCheckinAdminNotification.php +++ b/app/Notifications/ExpectedCheckinAdminNotification.php @@ -2,14 +2,9 @@ namespace App\Notifications; -use App\Models\Setting; -use App\Models\SnipeModel; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; -use Carbon\Carbon; class ExpectedCheckinAdminNotification extends Notification { @@ -32,28 +27,21 @@ class ExpectedCheckinAdminNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; $notifyBy[]='mail'; return $notifyBy; } - public function toSlack($notifiable) - { - - } - /** * Get the mail representation of the notification. * - * @param mixed $asset * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($params) + public function toMail() { $message = (new MailMessage)->markdown('notifications.markdown.report-expected-checkins', @@ -67,16 +55,4 @@ class ExpectedCheckinAdminNotification extends Notification } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/ExpectedCheckinNotification.php b/app/Notifications/ExpectedCheckinNotification.php index 3dc41950d9..e7262ae54e 100644 --- a/app/Notifications/ExpectedCheckinNotification.php +++ b/app/Notifications/ExpectedCheckinNotification.php @@ -2,14 +2,10 @@ namespace App\Notifications; -use App\Models\Setting; -use App\Models\SnipeModel; +use Carbon\Carbon; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; -use Illuminate\Support\Facades\Mail; -use Carbon\Carbon; class ExpectedCheckinNotification extends Notification { @@ -32,10 +28,9 @@ class ExpectedCheckinNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; $item = $this->params['item']; @@ -44,18 +39,12 @@ class ExpectedCheckinNotification extends Notification return $notifyBy; } - public function toSlack($notifiable) - { - - } - /** * Get the mail representation of the notification. * - * @param mixed $asset * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($params) + public function toMail() { $formatted_due = Carbon::parse($this->params->expected_checkin)->format('D, M j, Y'); return (new MailMessage) @@ -67,20 +56,6 @@ class ExpectedCheckinNotification extends Notification ->line('Serial: '.$this->params->serial) ->line('Asset Tag: '.$this->params->asset_tag) ->action('View Your Assets', route('view-assets')); - - } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/ExpiringAssetsNotification.php b/app/Notifications/ExpiringAssetsNotification.php index d130d26e27..47d5509259 100644 --- a/app/Notifications/ExpiringAssetsNotification.php +++ b/app/Notifications/ExpiringAssetsNotification.php @@ -28,28 +28,22 @@ class ExpiringAssetsNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; $notifyBy[]='mail'; return $notifyBy; } - public function toSlack($notifiable) - { - - } - /** * Get the mail representation of the notification. * * @param mixed $asset * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($params) + public function toMail() { $message = (new MailMessage)->markdown('notifications.markdown.report-expiring-assets', @@ -64,16 +58,4 @@ class ExpiringAssetsNotification extends Notification } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/ExpiringLicenseNotification.php b/app/Notifications/ExpiringLicenseNotification.php index 81798f6ca6..5ca1e93cf6 100644 --- a/app/Notifications/ExpiringLicenseNotification.php +++ b/app/Notifications/ExpiringLicenseNotification.php @@ -6,7 +6,6 @@ use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; - class ExpiringLicenseNotification extends Notification { use Queueable; @@ -32,25 +31,20 @@ class ExpiringLicenseNotification extends Notification * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { $notifyBy = []; $notifyBy[]='mail'; return $notifyBy; } - public function toSlack($notifiable) - { - - } - /** * Get the mail representation of the notification. * * @param mixed $asset * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($params) + public function toMail() { $message = (new MailMessage)->markdown('notifications.markdown.report-expiring-licenses', @@ -65,16 +59,4 @@ class ExpiringLicenseNotification extends Notification } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/FirstAdminNotification.php b/app/Notifications/FirstAdminNotification.php index bf802070da..153aff4aec 100644 --- a/app/Notifications/FirstAdminNotification.php +++ b/app/Notifications/FirstAdminNotification.php @@ -3,9 +3,8 @@ namespace App\Notifications; use Illuminate\Bus\Queueable; -use Illuminate\Notifications\Notification; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Notification; class FirstAdminNotification extends Notification { @@ -31,10 +30,9 @@ class FirstAdminNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { return ['mail']; } @@ -42,26 +40,13 @@ class FirstAdminNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { return (new MailMessage) ->subject(trans('mail.welcome', ['name' => $this->_data['first_name'] . ' ' . $this->_data['last_name'] ])) ->markdown('notifications.FirstAdmin', $this->_data); } - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/InventoryAlert.php b/app/Notifications/InventoryAlert.php index 3dee49134a..ff88b548c0 100644 --- a/app/Notifications/InventoryAlert.php +++ b/app/Notifications/InventoryAlert.php @@ -28,52 +28,31 @@ class InventoryAlert extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { - $notifyBy = []; - $notifyBy[]='mail'; + $notifyBy[] = 'mail'; + return $notifyBy; } - public function toSlack($notifiable) - { - - } - /** * Get the mail representation of the notification. * - * @param mixed $asset * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($params) + public function toMail() { - - $message = (new MailMessage)->markdown('notifications.markdown.report-low-inventory', + $message = (new MailMessage)->markdown( + 'notifications.markdown.report-low-inventory', [ 'items' => $this->items, 'threshold' => $this->threshold, - ]) + ] + ) ->subject(trans('mail.Low_Inventory_Report')); return $message; - - - } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; } } diff --git a/app/Notifications/MailTest.php b/app/Notifications/MailTest.php index 421cf7f988..65a6c63b77 100644 --- a/app/Notifications/MailTest.php +++ b/app/Notifications/MailTest.php @@ -4,9 +4,8 @@ namespace App\Notifications; use App\Models\Settings; use Illuminate\Bus\Queueable; -use Illuminate\Notifications\Notification; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Notification; class MailTest extends Notification { @@ -25,10 +24,9 @@ class MailTest extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { return ['mail']; } @@ -36,26 +34,12 @@ class MailTest extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { return (new MailMessage) ->subject(trans('mail.test_email')) ->markdown('notifications.Test'); } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/RequestAssetCancelation.php b/app/Notifications/RequestAssetCancelation.php index 3902f9af3b..d50aea3529 100644 --- a/app/Notifications/RequestAssetCancelation.php +++ b/app/Notifications/RequestAssetCancelation.php @@ -2,12 +2,13 @@ namespace App\Notifications; +use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -class RequestAssetCancelationNotification extends Notification +class RequestAssetCancelation extends Notification { /** * @var @@ -27,7 +28,7 @@ class RequestAssetCancelationNotification extends Notification $this->last_checkout = ''; $this->item_quantity = $params['item_quantity']; $this->expected_checkin = ''; - $this->requested_date = \App\Helpers\Helper::getFormattedDateObject($params['requested_date'], 'datetime', + $this->requested_date = Helper::getFormattedDateObject($params['requested_date'], 'datetime', false); $this->settings = Setting::getSettings(); @@ -36,16 +37,14 @@ class RequestAssetCancelationNotification extends Notification } if ($this->item->last_checkout) { - $this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date', + $this->last_checkout = Helper::getFormattedDateObject($this->item->last_checkout, 'date', false); } if ($this->item->expected_checkin) { - $this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date', + $this->expected_checkin = Helper::getFormattedDateObject($this->item->expected_checkin, 'date', false); } - - } /** @@ -72,8 +71,6 @@ class RequestAssetCancelationNotification extends Notification public function toSlack() { - - $target = $this->target; $item = $this->item; $note = $this->note; @@ -130,8 +127,6 @@ class RequestAssetCancelationNotification extends Notification return $message; - - } } diff --git a/app/Notifications/RequestAssetNotification.php b/app/Notifications/RequestAssetNotification.php index eac2cef22f..8c0c7d8505 100644 --- a/app/Notifications/RequestAssetNotification.php +++ b/app/Notifications/RequestAssetNotification.php @@ -2,6 +2,7 @@ namespace App\Notifications; +use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; @@ -28,7 +29,7 @@ class RequestAssetNotification extends Notification $this->note = ''; $this->last_checkout = ''; $this->expected_checkin = ''; - $this->requested_date = \App\Helpers\Helper::getFormattedDateObject($params['requested_date'], 'datetime', + $this->requested_date = Helper::getFormattedDateObject($params['requested_date'], 'datetime', false); $this->settings = Setting::getSettings(); @@ -37,12 +38,12 @@ class RequestAssetNotification extends Notification } if ($this->item->last_checkout) { - $this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date', + $this->last_checkout = Helper::getFormattedDateObject($this->item->last_checkout, 'date', false); } if ($this->item->expected_checkin) { - $this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date', + $this->expected_checkin = Helper::getFormattedDateObject($this->item->expected_checkin, 'date', false); } @@ -73,8 +74,6 @@ class RequestAssetNotification extends Notification public function toSlack() { - - $target = $this->target; $qty = $this->item_quantity; $item = $this->item; @@ -98,7 +97,6 @@ class RequestAssetNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail() @@ -127,8 +125,6 @@ class RequestAssetNotification extends Notification return $message; - - } } diff --git a/app/Notifications/SendUpcomingAuditNotification.php b/app/Notifications/SendUpcomingAuditNotification.php index 0aaf11cda5..a6863ea8e3 100644 --- a/app/Notifications/SendUpcomingAuditNotification.php +++ b/app/Notifications/SendUpcomingAuditNotification.php @@ -26,10 +26,9 @@ class SendUpcomingAuditNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { return $notifyBy = ['mail']; } @@ -37,10 +36,9 @@ class SendUpcomingAuditNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { $message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits', [ @@ -51,17 +49,4 @@ class SendUpcomingAuditNotification extends Notification return $message; } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Notifications/SlackTest.php b/app/Notifications/SlackTest.php deleted file mode 100644 index 213b21315e..0000000000 --- a/app/Notifications/SlackTest.php +++ /dev/null @@ -1,77 +0,0 @@ -from($settings->slack_botname, ':heart:') - ->to($settings->slack_channel) - ->image('https://snipeitapp.com/favicon.ico') - ->content('Oh hai! Looks like your Slack integration with Snipe-IT is working!'); - } - - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } -} diff --git a/app/Notifications/WelcomeNotification.php b/app/Notifications/WelcomeNotification.php index 837a4e6d8b..9a98a97734 100644 --- a/app/Notifications/WelcomeNotification.php +++ b/app/Notifications/WelcomeNotification.php @@ -3,9 +3,8 @@ namespace App\Notifications; use Illuminate\Bus\Queueable; -use Illuminate\Notifications\Notification; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Notification; class WelcomeNotification extends Notification { @@ -31,10 +30,9 @@ class WelcomeNotification extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable * @return array */ - public function via($notifiable) + public function via() { return ['mail']; } @@ -42,26 +40,12 @@ class WelcomeNotification extends Notification /** * Get the mail representation of the notification. * - * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail() { return (new MailMessage) ->subject(trans('mail.welcome', ['name' => $this->_data['first_name'] . ' ' . $this->_data['last_name'] ])) ->markdown('notifications.Welcome', $this->_data); } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } } diff --git a/app/Observers/AccessoryObserver.php b/app/Observers/AccessoryObserver.php index f84f12d116..1dd3e40437 100644 --- a/app/Observers/AccessoryObserver.php +++ b/app/Observers/AccessoryObserver.php @@ -3,7 +3,6 @@ namespace App\Observers; use App\Models\Accessory; -use App\Models\Setting; use App\Models\Actionlog; use Auth; diff --git a/app/Observers/AssetObserver.php b/app/Observers/AssetObserver.php index df466d3753..164792a3a9 100644 --- a/app/Observers/AssetObserver.php +++ b/app/Observers/AssetObserver.php @@ -2,9 +2,9 @@ namespace App\Observers; +use App\Models\Actionlog; use App\Models\Asset; use App\Models\Setting; -use App\Models\Actionlog; use Auth; class AssetObserver @@ -57,8 +57,9 @@ class AssetObserver */ public function created(Asset $asset) { - if ($settings = Setting::first()) { + if ($settings = Setting::getSettings()) { $settings->increment('next_auto_tag_base'); + $settings->save(); } $logAction = new Actionlog(); diff --git a/app/Observers/ComponentObserver.php b/app/Observers/ComponentObserver.php index 054520fc8e..3cb0aeda6c 100644 --- a/app/Observers/ComponentObserver.php +++ b/app/Observers/ComponentObserver.php @@ -2,9 +2,8 @@ namespace App\Observers; -use App\Models\Component; -use App\Models\Setting; use App\Models\Actionlog; +use App\Models\Component; use Auth; class ComponentObserver diff --git a/app/Observers/ConsumableObserver.php b/app/Observers/ConsumableObserver.php index 4b41df0782..22c94f2688 100644 --- a/app/Observers/ConsumableObserver.php +++ b/app/Observers/ConsumableObserver.php @@ -2,9 +2,8 @@ namespace App\Observers; -use App\Models\Consumable; -use App\Models\Setting; use App\Models\Actionlog; +use App\Models\Consumable; use Auth; class ConsumableObserver diff --git a/app/Observers/LicenseObserver.php b/app/Observers/LicenseObserver.php index 19c85ae923..5f0132f208 100644 --- a/app/Observers/LicenseObserver.php +++ b/app/Observers/LicenseObserver.php @@ -2,9 +2,8 @@ namespace App\Observers; -use App\Models\License; -use App\Models\Setting; use App\Models\Actionlog; +use App\Models\License; use Auth; class LicenseObserver diff --git a/app/Observers/SettingObserver.php b/app/Observers/SettingObserver.php new file mode 100644 index 0000000000..eea0240017 --- /dev/null +++ b/app/Observers/SettingObserver.php @@ -0,0 +1,23 @@ +hasAccess($this->columnName().'.delete'); + $itemConditional = true; + if ($item) { + $itemConditional = empty($item->deleted_at); + } + return $itemConditional && $user->hasAccess($this->columnName().'.delete'); } /** diff --git a/app/Policies/StatuslabelPolicy.php b/app/Policies/StatuslabelPolicy.php index ca9d554d8c..585404695f 100644 --- a/app/Policies/StatuslabelPolicy.php +++ b/app/Policies/StatuslabelPolicy.php @@ -2,8 +2,6 @@ namespace App\Policies; -use App\Policies\SnipePermissionsPolicy; - class StatuslabelPolicy extends SnipePermissionsPolicy { protected function columnName() diff --git a/app/Policies/SupplierPolicy.php b/app/Policies/SupplierPolicy.php index 6e1e5e1b90..979a99b996 100644 --- a/app/Policies/SupplierPolicy.php +++ b/app/Policies/SupplierPolicy.php @@ -2,8 +2,6 @@ namespace App\Policies; -use App\Policies\SnipePermissionsPolicy; - class SupplierPolicy extends SnipePermissionsPolicy { protected function columnName() diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php index e6db28c4cf..ee61ab2499 100644 --- a/app/Policies/UserPolicy.php +++ b/app/Policies/UserPolicy.php @@ -2,8 +2,6 @@ namespace App\Policies; -use App\Policies\SnipePermissionsPolicy; - class UserPolicy extends SnipePermissionsPolicy { protected function columnName() diff --git a/app/Presenters/AccessoryPresenter.php b/app/Presenters/AccessoryPresenter.php index 1dc0f77ef3..bf7074ad55 100644 --- a/app/Presenters/AccessoryPresenter.php +++ b/app/Presenters/AccessoryPresenter.php @@ -1,9 +1,6 @@ trans('admin/hardware/table.asset_tag'), "formatter" => "assetTagLinkFormatter" ], [ + "field" => "model", + "searchable" => true, + "sortable" => true, + "switchable" => true, + "title" => trans('admin/hardware/form.model'), + "visible" => false, + "formatter" => "modelsLinkObjFormatter" + ],[ "field" => "supplier", "searchable" => true, "sortable" => true, diff --git a/app/Presenters/AssetModelPresenter.php b/app/Presenters/AssetModelPresenter.php index 0e4b7dd350..5b9e66bc5c 100644 --- a/app/Presenters/AssetModelPresenter.php +++ b/app/Presenters/AssetModelPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class AssetModelPresenter * @package App\Presenters diff --git a/app/Presenters/CategoryPresenter.php b/app/Presenters/CategoryPresenter.php index bceff26c6b..c3af062f26 100644 --- a/app/Presenters/CategoryPresenter.php +++ b/app/Presenters/CategoryPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class CategoryPresenter * @package App\Presenters @@ -45,52 +43,35 @@ class CategoryPresenter extends Presenter "sortable" => true, "title" => trans('general.type'), "visible" => true - ], [ - "field" => "assets_count", + ],[ + "field" => "item_count", "searchable" => false, "sortable" => true, - "title" => trans('general.assets'), + "title" => trans('general.qty'), "visible" => true - ], [ - "field" => "accessories_count", - "searchable" => false, - "sortable" => true, - "title" => trans('general.accessories'), - "visible" => true - ], [ - "field" => "consumables_count", - "searchable" => false, - "sortable" => true, - "title" => trans('general.consumables'), - "visible" => true - ], [ - "field" => "components_count", - "searchable" => false, - "sortable" => true, - "title" => trans('general.components'), - "visible" => true - ], [ - "field" => "licenses_count", - "searchable" => false, - "sortable" => true, - "title" => trans('general.licenses'), - "visible" => true - ], [ - "field" => "eula", + ],[ + "field" => "has_eula", "searchable" => false, "sortable" => false, "title" => trans('admin/categories/table.eula_text'), "visible" => false, "formatter" => 'trueFalseFormatter', - ], [ + ],[ + "field" => "checkin_email", + "searchable" => false, + "sortable" => true, + "class" => 'css-envelope', + "title" => 'Send Email', + "visible" => true, + "formatter" => 'trueFalseFormatter', + ],[ "field" => "require_acceptance", "searchable" => false, "sortable" => true, "title" => trans('admin/categories/table.require_acceptance'), "visible" => true, "formatter" => 'trueFalseFormatter', - ], - [ + ],[ "field" => "actions", "searchable" => false, "sortable" => false, diff --git a/app/Presenters/CompanyPresenter.php b/app/Presenters/CompanyPresenter.php index 6ecba2e915..9f8e6fb376 100644 --- a/app/Presenters/CompanyPresenter.php +++ b/app/Presenters/CompanyPresenter.php @@ -82,12 +82,14 @@ class CompanyPresenter extends Presenter "sortable" => true, "visible" => false, "title" => trans('general.updated_at'), + "formatter" => 'createdAtFormatter', ],[ "field" => "created_at", "searchable" => false, "sortable" => true, "visible" => false, "title" => trans('general.created_at'), + "formatter" => 'createdAtFormatter', ],[ "field" => "actions", "searchable" => false, diff --git a/app/Presenters/ComponentPresenter.php b/app/Presenters/ComponentPresenter.php index c582e60a7c..669b5c651f 100644 --- a/app/Presenters/ComponentPresenter.php +++ b/app/Presenters/ComponentPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class ComponentPresenter * @package App\Presenters diff --git a/app/Presenters/DepreciationPresenter.php b/app/Presenters/DepreciationPresenter.php index c6b17c6348..6bbb538842 100644 --- a/app/Presenters/DepreciationPresenter.php +++ b/app/Presenters/DepreciationPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class DepreciationPresenter * @package App\Presenters diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index 4503895ca0..520b27e13f 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -2,9 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; -use Illuminate\Support\Facades\Gate; - /** * Class LicensePresenter * @package App\Presenters @@ -101,6 +98,21 @@ class LicensePresenter extends Presenter "title" => trans('general.purchase_date'), 'formatter' => 'dateDisplayFormatter' ], [ + "field" => "maintained", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/licenses/form.maintained'), + "formatter" => "trueFalseFormatter" + ], [ + "field" => "reassignable", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/licenses/form.reassignable'), + "formatter" => "trueFalseFormatter" + ], + [ "field" => "purchase_cost", "searchable" => true, "sortable" => true, @@ -164,6 +176,7 @@ class LicensePresenter extends Presenter "field" => "name", "searchable" => false, "sortable" => false, + "sorter" => "numericOnly", "switchable" => true, "title" => trans('admin/licenses/general.seat'), "visible" => true, diff --git a/app/Presenters/LicenseSeatPresenter.php b/app/Presenters/LicenseSeatPresenter.php new file mode 100644 index 0000000000..03f02cbd72 --- /dev/null +++ b/app/Presenters/LicenseSeatPresenter.php @@ -0,0 +1,15 @@ +model->license->name; + } +} diff --git a/app/Presenters/LocationPresenter.php b/app/Presenters/LocationPresenter.php index 442745131d..6a793d24cc 100644 --- a/app/Presenters/LocationPresenter.php +++ b/app/Presenters/LocationPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class LocationPresenter * @package App\Presenters diff --git a/app/Presenters/ManufacturerPresenter.php b/app/Presenters/ManufacturerPresenter.php index 85a72c1250..c78da85f00 100644 --- a/app/Presenters/ManufacturerPresenter.php +++ b/app/Presenters/ManufacturerPresenter.php @@ -2,8 +2,6 @@ namespace App\Presenters; -use App\Helpers\Helper; - /** * Class ManufacturerPresenter * @package App\Presenters diff --git a/app/Presenters/PredefinedKitPresenter.php b/app/Presenters/PredefinedKitPresenter.php new file mode 100644 index 0000000000..dddaff069f --- /dev/null +++ b/app/Presenters/PredefinedKitPresenter.php @@ -0,0 +1,293 @@ + "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => 'Name', // TODO: trans + "formatter" => "kitsLinkFormatter" + ] + ]; + + $layout[] = [ + "field" => "checkincheckout", + "searchable" => false, + "sortable" => false, + "switchable" => true, + "title" => trans('general.checkin').'/'.trans('general.checkout'), + "visible" => true, + "formatter" => "kitsInOutFormatter", + ]; + + $layout[] = [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "kitsActionsFormatter", + ]; + + + return json_encode($layout); + } + + + /** + * Json Column Layout for bootstrap table of kit models + * @return string + */ + public static function dataTableModels() + { + $layout = [ + [ + "field" => "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "pivot_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "owner_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => 'Name', // TODO: trans + "formatter" => "modelsLinkFormatter" + ], [ + "field" => "quantity", + "searchable" => false, + "sortable" => false, + "title" => 'Quantity', // TODO: trans + ], [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "kits_modelsActionsFormatter", + ] + ]; + + return json_encode($layout); + } + + /** + * Json Column Layout for bootstrap table of kit licenses + * @return string + */ + public static function dataTableLicenses() + { + $layout = [ + [ + "field" => "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "pivot_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "owner_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => 'Name', // TODO: trans + "formatter" => "licensesLinkFormatter" + ], [ + "field" => "quantity", + "searchable" => false, + "sortable" => false, + "title" => 'Quantity', // TODO: trans + ], [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "kits_licensesActionsFormatter", + ] + ]; + + return json_encode($layout); + } + + /** + * Json Column Layout for bootstrap table of kit accessories + * @return string + */ + public static function dataTableAccessories() + { + $layout = [ + [ + "field" => "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "pivot_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "owner_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => 'Name', // TODO: trans + "formatter" => "accessoriesLinkFormatter" + ], [ + "field" => "quantity", + "searchable" => false, + "sortable" => false, + "title" => 'Quantity', // TODO: trans + ], [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "kits_accessoriesActionsFormatter", + ] + ]; + + return json_encode($layout); + } + + + /** + * Json Column Layout for bootstrap table of kit consumables + * @return string + */ + public static function dataTableConsumables() + { + $layout = [ + [ + "field" => "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "pivot_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "owner_id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => 'Name', // TODO: trans + "formatter" => "consumablesLinkFormatter" + ], [ + "field" => "quantity", + "searchable" => false, + "sortable" => false, + "title" => 'Quantity', // TODO: trans + ], [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "kits_consumablesActionsFormatter", + ] + ]; + + return json_encode($layout); + } + + + /** + * Link to this kit Name + * @return string + */ + public function nameUrl() + { + return (string)link_to_route('kits.show', $this->name, $this->id); + } + + /** + * @return string + */ + public function fullName() + { + return $this->name; + } + + /** + * Url to view this item. + * @return string + */ + public function viewUrl() + { + return route('kits.show', $this->id); + } +} diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index c2d0253fa5..b9d539c069 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -6,6 +6,7 @@ use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Storage; /** * Class UserPresenter @@ -320,8 +321,9 @@ class UserPresenter extends Presenter public function gravatar() { + if ($this->avatar) { - return config('app.url').'/uploads/avatars/'.$this->avatar; + return Storage::disk('public')->url('avatars/'.e($this->avatar)); } if (Setting::getSettings()->load_remote=='1') { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 35f392f9e1..c4f5c731d1 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,20 +2,20 @@ namespace App\Providers; -use Illuminate\Support\ServiceProvider; -use Log; -use Illuminate\Support\Facades\Schema; -use App\Observers\AssetObserver; -use App\Observers\LicenseObserver; -use App\Observers\AccessoryObserver; -use App\Observers\ConsumableObserver; -use App\Observers\ComponentObserver; -use App\Models\Asset; -use App\Models\License; use App\Models\Accessory; -use App\Models\Consumable; +use App\Models\Asset; use App\Models\Component; - +use App\Models\Consumable; +use App\Models\License; +use App\Models\Setting; +use App\Observers\AccessoryObserver; +use App\Observers\AssetObserver; +use App\Observers\ComponentObserver; +use App\Observers\ConsumableObserver; +use App\Observers\LicenseObserver; +use App\Observers\SettingObserver; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\ServiceProvider; /** * This service provider handles setting the observers on models @@ -41,8 +41,7 @@ class AppServiceProvider extends ServiceProvider Component::observe(ComponentObserver::class); Consumable::observe(ConsumableObserver::class); License::observe(LicenseObserver::class); - - + Setting::observe(SettingObserver::class); } /** @@ -52,15 +51,10 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - $monolog = Log::getMonolog(); - $log_level = config('app.log_level'); if (($this->app->environment('production')) && (config('services.rollbar.access_token'))){ $this->app->register(\Rollbar\Laravel\RollbarServiceProvider::class); } - - foreach ($monolog->getHandlers() as $handler) { - $handler->setLevel($log_level); - } + } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 2c8e07e518..b0c219ba1e 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -6,23 +6,24 @@ use App\Models\Accessory; use App\Models\Asset; use App\Models\AssetModel; use App\Models\Category; +use App\Models\Company; use App\Models\Component; use App\Models\Consumable; use App\Models\CustomField; use App\Models\CustomFieldset; use App\Models\Department; +use App\Models\Depreciation; use App\Models\License; use App\Models\Location; -use App\Models\Depreciation; +use App\Models\Manufacturer; use App\Models\Statuslabel; use App\Models\Supplier; -use App\Models\Manufacturer; -use App\Models\Company; use App\Models\User; use App\Policies\AccessoryPolicy; use App\Policies\AssetModelPolicy; use App\Policies\AssetPolicy; use App\Policies\CategoryPolicy; +use App\Policies\CompanyPolicy; use App\Policies\ComponentPolicy; use App\Policies\ConsumablePolicy; use App\Policies\CustomFieldPolicy; @@ -31,11 +32,10 @@ use App\Policies\DepartmentPolicy; use App\Policies\DepreciationPolicy; use App\Policies\LicensePolicy; use App\Policies\LocationPolicy; +use App\Policies\ManufacturerPolicy; use App\Policies\StatuslabelPolicy; use App\Policies\SupplierPolicy; use App\Policies\UserPolicy; -use App\Policies\ManufacturerPolicy; -use App\Policies\CompanyPolicy; use Carbon\Carbon; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Gate; @@ -89,6 +89,7 @@ class AuthServiceProvider extends ServiceProvider Passport::routes(); Passport::tokensExpireIn(Carbon::now()->addYears(20)); Passport::refreshTokensExpireIn(Carbon::now()->addYears(20)); + Passport::withCookieSerialization(); // -------------------------------- @@ -147,6 +148,10 @@ class AuthServiceProvider extends ServiceProvider return $user->hasAccess('self.edit_location'); }); + Gate::define('self.checkout_assets', function($user) { + return $user->hasAccess('self.checkout_assets'); + }); + Gate::define('backend.interact', function ($user) { return $user->can('view', Statuslabel::class) || $user->can('view', AssetModel::class) diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 9d3e0f8a98..a67715fc12 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,7 +2,8 @@ namespace App\Providers; -use Illuminate\Support\Facades\Event; +use App\Listeners\CheckoutableListener; +use App\Listeners\LogListener; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider @@ -13,26 +14,22 @@ class EventServiceProvider extends ServiceProvider * @var array */ protected $listen = [ + 'Illuminate\Auth\Events\Login' => [ + 'App\Listeners\LogSuccessfulLogin', + ], - 'Illuminate\Auth\Events\Login' => [ - 'App\Listeners\LogSuccessfulLogin', - ], - - 'Illuminate\Auth\Events\Failed' => [ - 'App\Listeners\LogFailedLogin', - ], - ]; - + 'Illuminate\Auth\Events\Failed' => [ + 'App\Listeners\LogFailedLogin', + ], + ]; /** - * Register any events for your application. + * The subscriber classes to register. * - * @return void + * @var array */ - public function boot() - { - parent::boot(); - - // - } + protected $subscribe = [ + LogListener::class, + CheckoutableListener::class + ]; } diff --git a/app/Providers/LdapServiceProvider.php b/app/Providers/LdapServiceProvider.php new file mode 100644 index 0000000000..cc91bac1a5 --- /dev/null +++ b/app/Providers/LdapServiceProvider.php @@ -0,0 +1,29 @@ +app->singleton(LdapAd::class, LdapAd::class); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 94f5ca0bf3..f52cdcae15 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,8 +2,8 @@ namespace App\Providers; -use Illuminate\Support\Facades\Route; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; +use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { @@ -63,6 +63,7 @@ class RouteServiceProvider extends ServiceProvider require base_path('routes/web/fields.php'); require base_path('routes/web/components.php'); require base_path('routes/web/users.php'); + require base_path('routes/web/kits.php'); require base_path('routes/web.php'); }); } diff --git a/app/Providers/SamlServiceProvider.php b/app/Providers/SamlServiceProvider.php new file mode 100644 index 0000000000..edf40dd3d8 --- /dev/null +++ b/app/Providers/SamlServiceProvider.php @@ -0,0 +1,69 @@ +app->singleton(Saml::class, Saml::class); + + Route::group(['namespace'=> 'App\Http\Controllers'], function () { + Route::group(['prefix'=> 'saml'], function () { + Route::get( + 'metadata', + [ + 'as' => 'saml.metadata', + 'uses' => 'Auth\SamlController@metadata' ] + ); + + Route::match( + ['get', 'post'], + 'acs', + [ + 'as' => 'saml.acs', + 'uses' => 'Auth\SamlController@acs' ] + ); + + Route::get( + 'sls', + [ + 'as' => 'saml.sls', + 'uses' => 'Auth\SamlController@sls' ] + ); + }); + + Route::get( + 'login/saml', + [ + 'as' => 'saml.login', + 'uses' => 'Auth\SamlController@login' ] + ); + + Route::group(['prefix' => 'admin','middleware' => ['auth', 'authorize:superuser']], function () { + + Route::get('saml', ['as' => 'settings.saml.index','uses' => 'SettingsController@getSamlSettings' ]); + Route::post('saml', ['as' => 'settings.saml.save','uses' => 'SettingsController@postSamlSettings' ]); + + }); + }); + } + + /** + * Register the application services. + * + * @return void + */ + public function register() + { + } +} diff --git a/app/Providers/SettingsServiceProvider.php b/app/Providers/SettingsServiceProvider.php index 7577b94f5b..adf25b6435 100644 --- a/app/Providers/SettingsServiceProvider.php +++ b/app/Providers/SettingsServiceProvider.php @@ -1,12 +1,8 @@ composer('*', function ($view) { - $view->with('snipeSettings', \App\Models\Setting::getSettings()); + $view->with('snipeSettings', Setting::getSettings()); }); @@ -39,104 +35,116 @@ class SettingsServiceProvider extends ServiceProvider * Set some common variables so that they're globally available. * The paths should always be public (versus private uploads) */ + + + // Model paths and URLs + + \App::singleton('assets_upload_path', function(){ + return 'assets/'; + }); + + \App::singleton('accessories_upload_path', function() { + return 'public/uploads/accessories/'; + }); + \App::singleton('models_upload_path', function(){ - return public_path('/uploads/models/'); + return 'models/'; }); \App::singleton('models_upload_url', function(){ - return url('/').'/uploads/models/'; + return 'models/'; }); // Categories \App::singleton('categories_upload_path', function(){ - return public_path('/uploads/categories/'); + return 'categories/'; }); \App::singleton('categories_upload_url', function(){ - return url('/').'/uploads/categories/'; + return 'categories/'; }); // Locations \App::singleton('locations_upload_path', function(){ - return public_path('/uploads/locations/'); + return 'locations/'; }); \App::singleton('locations_upload_url', function(){ - return url('/').'/uploads/locations/'; + return 'locations/'; }); // Users \App::singleton('users_upload_path', function(){ - return public_path('/uploads/users/'); + return 'avatars/'; }); \App::singleton('users_upload_url', function(){ - return url('/').'/uploads/users/'; + return 'users/'; }); // Manufacturers \App::singleton('manufacturers_upload_path', function(){ - return public_path('/uploads/manufacturers/'); + return 'manufacturers/'; }); \App::singleton('manufacturers_upload_url', function(){ - return url('/').'/uploads/manufacturers/'; + return 'manufacturers/'; }); // Suppliers \App::singleton('suppliers_upload_path', function(){ - return public_path('/uploads/suppliers/'); + return 'suppliers/'; }); \App::singleton('suppliers_upload_url', function(){ - return url('/').'/uploads/suppliers/'; + return 'suppliers/'; }); // Departments \App::singleton('departments_upload_path', function(){ - return public_path('/uploads/departments/'); + return 'departments/'; }); \App::singleton('departments_upload_url', function(){ - return url('/').'/uploads/departments/'; + return 'departments/'; }); // Company paths and URLs \App::singleton('companies_upload_path', function(){ - return public_path('/uploads/companies/'); + return 'companies/'; }); \App::singleton('companies_upload_url', function(){ - return url('/').'/uploads/companies/'; + return 'companies/'; }); // Accessories paths and URLs \App::singleton('accessories_upload_path', function(){ - return public_path('/uploads/accessories/'); + return 'accessories/'; }); \App::singleton('accessories_upload_url', function(){ - return url('/').'/uploads/accessories/'; + return 'accessories/'; }); // Consumables paths and URLs \App::singleton('consumables_upload_path', function(){ - return public_path('/uploads/consumables/'); + return 'consumables/'; }); \App::singleton('consumables_upload_url', function(){ - return url('/').'/uploads/consumables/'; + return 'consumables/'; }); // Components paths and URLs \App::singleton('components_upload_path', function(){ - return public_path('/uploads/components/'); + return 'components/'; }); \App::singleton('components_upload_url', function(){ - return url('/').'/uploads/components/'; + return 'components/'; }); diff --git a/app/Providers/ValidationServiceProvider.php b/app/Providers/ValidationServiceProvider.php index 78f5f2c4e6..1fd815084a 100644 --- a/app/Providers/ValidationServiceProvider.php +++ b/app/Providers/ValidationServiceProvider.php @@ -1,22 +1,9 @@ + * + * @since 5.0.0 + */ +class LdapAd extends LdapAdConfiguration +{ + /** + * @see https://wdmsb.wordpress.com/2014/12/03/descriptions-of-active-directory-useraccountcontrol-value/ + */ + const AD_USER_ACCOUNT_CONTROL_FLAGS = ['512', '544', '66048', '66080', '262656', '262688', '328192', '328224']; + + /** + * The LDAP results per page. + */ + const PAGE_SIZE = 500; + + /** + * A base dn. + * + * @var string + */ + public $baseDn = null; + + /** + * Adldap instance. + * + * @var \Adldap\Adldap + */ + protected $ldap; + + /** + * Initialize LDAP from user settings + * + * @since 5.0.0 + * + * @return void + */ + public function init() + { + // Already initialized + if ($this->ldap) { + return true; + } + + parent::init(); + if($this->isLdapEnabled()) { + $this->ldapConfig['account_prefix'] = $this->ldapSettings['ldap_auth_filter_query']; + $this->ldapConfig['account_suffix'] = ','.$this->ldapConfig['base_dn']; + $this->ldap = new Adldap(); + $this->ldap->addProvider($this->ldapConfig); + return true; + } + return false; + } + + public function __construct() { + $this->init(); + } + + /** + * Create a user if they successfully login to the LDAP server. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param string $username + * @param string $password + * + * @return \App\Models\User + * + * @throws Exception + */ + public function ldapLogin(string $username, string $password): User + { + if ($this->ldapSettings['ad_append_domain']) { + $username .= '@' . $this->ldapSettings['ad_domain']; + } + + if ($this->ldap->auth()->attempt($username, $password, true) === false) { + throw new Exception('Unable to validate user credentials!'); + } + + // Should we sync the logged in user + Log::debug('Attempting to find user in LDAP directory'); + $record = $this->ldap->search()->findBy($this->ldapSettings['ldap_username_field'], $username); + + if($record) { + if ($this->isLdapSync($record)) { + $this->syncUserLdapLogin($record, $password); + } + } + else { + throw new Exception('Unable to find user in LDAP directory!'); + } + + return User::where('username', $username) + ->whereNull('deleted_at')->where('ldap_import', '=', 1) + ->where('activated', '=', '1')->first(); + } + + /** + * Set the user information based on the LDAP settings. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $user + * @param null|Collection $defaultLocation + * @param null|Collection $mappedLocations + * + * @return null|\App\Models\User + */ + public function processUser(AdldapUser $user, ?Collection $defaultLocation=null, ?Collection $mappedLocations=null): ?User + { + // Only sync active users + if(!$user) { + return null; + } + $snipeUser = []; + $snipeUser['username'] = $user->{$this->ldapSettings['ldap_username_field']}[0] ?? ''; + $snipeUser['employee_number'] = $user->{$this->ldapSettings['ldap_emp_num']}[0] ?? ''; + $snipeUser['lastname'] = $user->{$this->ldapSettings['ldap_lname_field']}[0] ?? ''; + $snipeUser['firstname'] = $user->{$this->ldapSettings['ldap_fname_field']}[0] ?? ''; + $snipeUser['email'] = $user->{$this->ldapSettings['ldap_email']}[0] ?? ''; + $snipeUser['title'] = $user->getTitle() ?? ''; + $snipeUser['telephonenumber'] = $user->getTelephoneNumber() ?? ''; + $snipeUser['location_id'] = $this->getLocationId($user, $defaultLocation, $mappedLocations); + $snipeUser['activated'] = $this->getActiveStatus($user); + + return $this->setUserModel($snipeUser); + } + + /** + * Set the User model information. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param array $userInfo The user info to save to the database + * + * @return \App\Models\User + */ + public function setUserModel(array $userInfo): User + { + // If the username exists, return the user object, otherwise create a new user object + $user = User::firstOrNew([ + 'username' => $userInfo['username'], + ]); + $user->username = $user->username ?? trim($userInfo['username']); + $user->password = $user->password ?? Helper::generateEncyrptedPassword(); + $user->first_name = trim($userInfo['firstname']); + $user->last_name = trim($userInfo['lastname']); + $user->email = trim($userInfo['email']); + $user->employee_num = trim($userInfo['employee_number']); + $user->jobtitle = trim($userInfo['title']); + $user->phone = trim($userInfo['telephonenumber']); + $user->activated = $userInfo['activated']; + $user->location_id = $userInfo['location_id']; + $user->notes = 'Imported from LDAP'; + $user->ldap_import = 1; + + return $user; + } + + /** + * Sync a user who has logged in by LDAP. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $record + * @param string $password + * + * @throws Exception + */ + private function syncUserLdapLogin(AdldapUser $record, string $password): void + { + $user = $this->processUser($record); + + if (is_null($user->last_login)) { + $user->notes = 'Imported on first login from LDAP2'; + } + + if ($this->ldapSettings['ldap_pw_sync']) { + Log::debug('Syncing users password with LDAP directory.'); + $user->password = bcrypt($password); + } + + if (!$user->save()) { + Log::debug('Could not save user. '.$user->getErrors()); + throw new Exception('Could not save user: '.$user->getErrors()); + } + } + + /** + * Check to see if we should sync the user with the LDAP directory. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $user + * + * @return bool + */ + private function isLdapSync(AdldapUser $user): bool + { + return (false == $this->ldapSettings['ldap_active_flag']) + || ('true' == strtolower($user->{$this->ldapSettings['ldap_active_flag']}[0])); + } + + /** + * Set the active status of the user. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $user + * + * @return int + */ + private function getActiveStatus(AdldapUser $user): int + { + $activeStatus = 0; + /* + * Check to see if we are connected to an AD server + * if so, check the Active Directory User Account Control Flags + */ + if ($user->hasAttribute($user->getSchema()->userAccountControl())) { + $activeStatus = (in_array($user->getUserAccountControl(), self::AD_USER_ACCOUNT_CONTROL_FLAGS)) ? 1 : 0; + } else { + // If there is no activated flag, assume this is handled via the OU and activate the users + if (false == $this->ldapSettings['ldap_active_flag']) { + $activeStatus = 1; + } + } + + return $activeStatus; + } + + /** + * Get a default selected location, or a OU mapped location if available. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @param \Adldap\Models\User $user + * @param Collection|null $defaultLocation + * @param Collection|null $mappedLocations + * + * @return null|int + */ + private function getLocationId(AdldapUser $user, ?Collection $defaultLocation, ?Collection $mappedLocations): ?int + { + $locationId = null; + // Set the users default locations, if set + if ($defaultLocation) { + $locationId = $defaultLocation->keys()->first(); + } + + // Check to see if the user is in a mapped location + if ($mappedLocations) { + $location = $mappedLocations->filter(function ($value, $key) use ($user) { + if ($user->inOu($value)) { + return $key; + } + }); + + if ($location->count() > 0) { + $locationId = $location->keys()->first(); + } + } + + return $locationId; + } + + /** + * Get the base dn for the query. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return string + */ + private function getBaseDn(): string + { + if (!is_null($this->baseDn)) { + return $this->baseDn; + } + + return $this->ldapSettings['ldap_basedn']; + } + + /** + * Format the ldap filter if needed. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return null|string + */ + private function getFilter(): ?string + { + $filter = $this->ldapSettings['ldap_filter']; + if (!$filter) { + return null; + } + // Add surrounding parentheses as needed + $paren = mb_substr($filter, 0, 1, 'utf-8'); + if ('(' !== $paren) { + return '('.$filter.')'; + } + + return $filter; + } + + /** + * Get the selected fields to return + * This should help with memory on large result sets as we are not returning all fields. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return array + */ + private function getSelectedFields(): array + { + /** @var Schema $schema */ + $schema = new $this->ldapConfig['schema']; + return [ + $this->ldapSettings['ldap_username_field'], + $this->ldapSettings['ldap_fname_field'], + $this->ldapSettings['ldap_lname_field'], + $this->ldapSettings['ldap_email'], + $this->ldapSettings['ldap_emp_num'], + $this->ldapSettings['ldap_active_flag'], + $schema->memberOf(), + $schema->userAccountControl(), + $schema->title(), + $schema->telephone(), + ]; + } + + /** + * Test the bind user connection. + * + * @author Wes Hulette + * @throws \Exception + * @since 5.0.0 + */ + public function testLdapAdBindConnection(): void + { + try { + $this->ldap->search()->ous()->get()->count(); //it's saying this is null? + } catch (Exception $th) { + Log::error($th->getMessage()); + throw new Exception('Unable to search LDAP directory!'); + } + } + + /** + * Test the user can connect to the LDAP server. + * + * @author Wes Hulette + * @throws \Exception + * @since 5.0.0 + */ + public function testLdapAdUserConnection(): void + { + try { + $this->ldap->connect(); //uh, this doesn't seem to exist :/ + } catch (\Adldap\Auth\BindException $e) { + Log::error($e); + throw new Exception('Unable to connect to LDAP directory!'); + } + } + + /** + * Test the LDAP configuration by returning up to 10 users. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return Collection + */ + public function testUserImportSync(): Collection + { + $testUsers = collect($this->getLdapUsers()->getResults())->chunk(10)->first(); + if ($testUsers) { + return $testUsers->map(function ($item) { + return (object) [ + 'username' => $item->{$this->ldapSettings['ldap_username_field']}[0] ?? null, + 'employee_number' => $item->{$this->ldapSettings['ldap_emp_num']}[0] ?? null, + 'lastname' => $item->{$this->ldapSettings['ldap_lname_field']}[0] ?? null, + 'firstname' => $item->{$this->ldapSettings['ldap_fname_field']}[0] ?? null, + 'email' => $item->{$this->ldapSettings['ldap_email']}[0] ?? null, + ]; + }); + } + + return collect(); + } + + /** + * Query the LDAP server to get the users to process and return a page set. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return \Adldap\Query\Paginator + */ + public function getLdapUsers(): Paginator + { + $search = $this->ldap->search()->users()->in($this->getBaseDn()); //this looks wrong; we should instead have a passable parameter that does this, and use this as a 'sane' default, yeah? + + $filter = $this->getFilter(); + if (!is_null($filter)) { + $search = $search->rawFilter($filter); + } + + return $search->select($this->getSelectedFields()) + ->paginate(self::PAGE_SIZE); + } +} diff --git a/app/Services/LdapAdConfiguration.php b/app/Services/LdapAdConfiguration.php new file mode 100644 index 0000000000..8c912edb53 --- /dev/null +++ b/app/Services/LdapAdConfiguration.php @@ -0,0 +1,296 @@ + + * + * @since 5.0.0 + */ +class LdapAdConfiguration +{ + const LDAP_PORT = 389; + const CONNECTION_TIMEOUT = 5; + const DEFAULT_LDAP_VERSION = 3; + const LDAP_BOOLEAN_SETTINGS = [ + 'ldap_enabled', + 'ldap_server_cert_ignore', + 'ldap_tls', + 'ldap_tls', + 'ldap_pw_sync', + 'is_ad', + 'ad_append_domain', + ]; + + /** + * Ldap Settings. + * + * @var Collection + */ + public $ldapSettings; + + /** + * LDAP Config. + * + * @var array + */ + public $ldapConfig; + + /** + * Initialize LDAP from user settings + * + * @since 5.0.0 + */ + public function init() { + + // This try/catch is dumb, but is necessary to run initial migrations, since + // this service provider is booted even during migrations. :( - snipe + try { + $this->ldapSettings = $this->getSnipeItLdapSettings(); + if ($this->isLdapEnabled()) { + $this->setSnipeItConfig(); + } + } catch (\Exception $e) { + \Log::debug($e); + $this->ldapSettings = null; + } + + } + + /** + * Merge the default Adlap config with the SnipeIT config. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function setSnipeItConfig() + { + $this->ldapConfig = $this->setLdapConnectionConfiguration(); + $this->certificateCheck(); + } + + /** + * Get the LDAP settings from the Settings model. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return \Illuminate\Support\Collection + */ + private function getSnipeItLdapSettings(): Collection + { + $ldapSettings = collect(); + if(Setting::first()) { // during early migration steps, there may be no settings table entry to start with + $ldapSettings = Setting::getLdapSettings() + ->map(function ($item, $key) { + // Trim the items + if (is_string($item)) { + $item = trim($item); + } + // Get the boolean value of the LDAP setting, makes it easier to work with them + if (in_array($key, self::LDAP_BOOLEAN_SETTINGS)) { + return boolval($item); + } + + // Decrypt the admin password + if ('ldap_pword' === $key && !empty($item)) { + try { + return decrypt($item); + } catch (Exception $e) { + throw new Exception('Your app key has changed! Could not decrypt LDAP password using your current app key, so LDAP authentication has been disabled. Login with a local account, update the LDAP password and re-enable it in Admin > Settings.'); + } + } + + if ($item && 'ldap_server' === $key) { + return collect(parse_url($item)); + } + + return $item; + }); + } + return $ldapSettings; + } + + /** + * Set the server certificate environment variable. + * + * @author Wes Hulette + * + * @since 5.0.0 + */ + private function certificateCheck(): void + { + // If we are ignoring the SSL cert we need to setup the environment variable + // before we create the connection + if ($this->ldapSettings['ldap_server_cert_ignore']) { + putenv('LDAPTLS_REQCERT=never'); + } + + // If the user specifies where CA Certs are, make sure to use them + if (env('LDAPTLS_CACERT')) { + putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT')); + } + } + + /** + * Set the Adlap2 connection configuration values based on SnipeIT settings. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return array + */ + private function setLdapConnectionConfiguration(): array + { + // Create the configuration array. + return [ + // Mandatory Configuration Options + 'hosts' => $this->getServerUrlBase(), + 'base_dn' => $this->ldapSettings['ldap_basedn'], + 'username' => $this->ldapSettings['ldap_uname'], + 'password' => $this->ldapSettings['ldap_pword'], + + // Optional Configuration Options + 'schema' => $this->getSchema(), // FIXME - we probably ought not to be using this, right? + 'account_prefix' => '', + 'account_suffix' => '', + 'port' => $this->getPort(), + 'follow_referrals' => false, + 'use_ssl' => $this->isSsl(), + 'use_tls' => $this->ldapSettings['ldap_tls'], + 'version' => $this->ldapSettings['ldap_version'] ?? self::DEFAULT_LDAP_VERSION, + 'timeout' => self::CONNECTION_TIMEOUT, + + // Custom LDAP Options + 'custom_options' => [ + // See: http://php.net/ldap_set_option + // LDAP_OPT_X_TLS_REQUIRE_CERT => LDAP_OPT_X_TLS_HARD, + ], + ]; + } + + /** + * Get the schema to use for the connection. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return string + */ + private function getSchema(): string //wait, what? This is a little weird, since we have completely separate variables for this; we probably shoulnd't be using any 'schema' at all + { + $schema = \Adldap\Schemas\OpenLDAP::class; + if ($this->ldapSettings['is_ad']) { + $schema = \Adldap\Schemas\ActiveDirectory::class; + } + + return $schema; + } + + /** + * Get the port number from the connection url. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return int + */ + private function getPort(): int + { + $port = $this->getLdapServerData('port'); + if ($port && is_int($port)) { + return $port; + } + return self::LDAP_PORT; + } + + /** + * Get ldap scheme from url to determin ssl use. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return bool + */ + private function isSsl(): bool + { + $scheme = $this->getLdapServerData('scheme'); + if ($scheme && 'ldaps' === strtolower($scheme)) { + return true; + } + return false; + } + + /** + * Return the base url to the LDAP server. + * + * @author Wes Hulette + * + * @since 5.0.0 + * + * @return array + */ + private function getServerUrlBase(): array + { + if ($this->ldapSettings['is_ad']) { + return collect(explode(',', $this->ldapSettings['ad_domain']))->map(function ($item) { + return trim($item); + })->toArray(); + } + + $url = $this->getLdapServerData('host'); + return $url ? [$url] : []; + } + + /** + * Get ldap enabled setting + * + * @author Steffen Buehl + * + * @since 5.0.0 + * + * @return bool + */ + public function isLdapEnabled(): bool + { + return $this->ldapSettings && $this->ldapSettings->get('ldap_enabled'); + } + + /** + * Get parsed ldap server information + * + * @author Steffen Buehl + * + * @since 5.0.0 + * + * @param $key + * @return mixed|null + */ + protected function getLdapServerData($key) + { + if ($this->ldapSettings) { + $ldapServer = $this->ldapSettings->get('ldap_server'); + if ($ldapServer && $ldapServer instanceof Collection) { + return $ldapServer->get($key); + } + } + + return null; + } +} diff --git a/app/Services/PredefinedKitCheckoutService.php b/app/Services/PredefinedKitCheckoutService.php new file mode 100644 index 0000000000..8a1c624cbe --- /dev/null +++ b/app/Services/PredefinedKitCheckoutService.php @@ -0,0 +1,192 @@ +] + */ +class PredefinedKitCheckoutService +{ + use AuthorizesRequests; + /** + * @param Request $request, this function works with fields: checkout_at, expected_checkin, note + * @param PredefinedKit $kit kit for checkout + * @param User $user checkout target + * @return array Empty array if all ok, else [string_error1, string_error2...] + */ + public function checkout(Request $request, PredefinedKit $kit, User $user) + { + try { + + // Check if the user exists + if (is_null($user)) { + return ['errors' => trans('admin/users/message.user_not_found')]; + } + + $errors = []; + + $assets_to_add = $this->getAssetsToAdd($kit, $user, $errors); + $license_seats_to_add = $this->getLicenseSeatsToAdd($kit, $errors); + $consumables_to_add = $this->getConsumablesToAdd($kit, $errors); + $accessories_to_add = $this->getAccessoriesToAdd($kit, $errors); + + if (count($errors) > 0) { + return ['errors' => $errors]; + } + + $checkout_at = date("Y-m-d H:i:s"); + if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date("Y-m-d"))) { + $checkout_at = $request->get('checkout_at'); + } + + $expected_checkin = ''; + if ($request->filled('expected_checkin')) { + $expected_checkin = $request->get('expected_checkin'); + } + + $admin = Auth::user(); + + $note = e($request->get('note')); + + $errors = $this->saveToDb($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $license_seats_to_add, $consumables_to_add, $accessories_to_add, $note); + + return ['errors' => $errors, 'assets' => $assets_to_add, 'accessories' => $accessories_to_add, 'consumables' => $consumables_to_add ]; + } catch (ModelNotFoundException $e) { + return ['errors' => [$e->getMessage()]]; + } catch (CheckoutNotAllowed $e) { + return ['errors' => [$e->getMessage()]]; + } + } + + protected function getAssetsToAdd($kit, $user, &$errors) + { + $models = $kit->models() + ->with(['assets' => function ($hasMany) { + $hasMany->RTD(); + }]) + ->get(); + $assets_to_add = []; + foreach ($models as $model) { + $assets = $model->assets; + $quantity = $model->pivot->quantity; + foreach ($assets as $asset) { + + if ( + $asset->availableForCheckout() + && !$asset->is($user) + ) { + + $this->authorize('checkout', $asset); + $quantity -= 1; + $assets_to_add[] = $asset; + if ($quantity <= 0) { + break; + } + } + } + if ($quantity > 0) { + $errors[] = trans('admin/kits/general.none_models', ['model'=> $model->name, 'qty' => $model->pivot->quantity]); + } + } + + return $assets_to_add; + } + + protected function getLicenseSeatsToAdd($kit, &$errors) + { + $seats_to_add = []; + $licenses = $kit->licenses() + ->with('freeSeats') + ->get(); + foreach ($licenses as $license) { + $quantity = $license->pivot->quantity; + if ($quantity > count($license->freeSeats)) { + $errors[] = trans('admin/kits/general.none_licenses', ['license'=> $license->name, 'qty' => $license->pivot->quantity]); + } + for ($i = 0; $i < $quantity; $i++) { + $seats_to_add[] = $license->freeSeats[$i]; + } + } + return $seats_to_add; + } + + protected function getConsumablesToAdd($kit, &$errors) + { + $consumables = $kit->consumables()->with('users')->get(); + foreach ($consumables as $consumable) { + if ($consumable->numRemaining() < $consumable->pivot->quantity) { + $errors[] = trans('admin/kits/general.none_consumables', ['consumable'=> $consumable->name, 'qty' => $consumable->pivot->quantity]); + } + } + return $consumables; + } + + protected function getAccessoriesToAdd($kit, &$errors) + { + $accessories = $kit->accessories()->with('users')->get(); + foreach ($accessories as $accessory) { + if ($accessory->numRemaining() < $accessory->pivot->quantity) { + $errors[] = trans('admin/kits/general.none_accessory', ['accessory'=> $accessory->name, 'qty' => $accessory->pivot->quantity]); + } + } + return $accessories; + } + + protected function saveToDb($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $license_seats_to_add, $consumables_to_add, $accessories_to_add, $note) + { + $errors = DB::transaction( + function () use ($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $license_seats_to_add, $consumables_to_add, $accessories_to_add, $note) { + // assets + foreach ($assets_to_add as $asset) { + $asset->location_id = $user->location_id; + $error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, $note, null); + if ($error) { + array_merge_recursive($errors, $asset->getErrors()->toArray()); + } + } + // licenses + foreach ($license_seats_to_add as $licenseSeat) { + $licenseSeat->user_id = $admin->id; + $licenseSeat->assigned_to = $user->id; + if ($licenseSeat->save()) { + event(new CheckoutableCheckedOut($licenseSeat, $user, $admin, $note)); + } else { + $errors[] = 'Something went wrong saving a license seat'; + } + } + // consumables + foreach ($consumables_to_add as $consumable) { + $consumable->assigned_to = $user->id; + $consumable->users()->attach($consumable->id, [ + 'consumable_id' => $consumable->id, + 'user_id' => $admin->id, + 'assigned_to' => $user->id + ]); + event(new CheckoutableCheckedOut($consumable, $user, $admin, $note)); + } + //accessories + foreach ($accessories_to_add as $accessory) { + $accessory->assigned_to = $user->id; + $accessory->users()->attach($accessory->id, [ + 'accessory_id' => $accessory->id, + 'user_id' => $admin->id, + 'assigned_to' => $user->id + ]); + event(new CheckoutableCheckedOut($accessory, $user, $admin, $note)); + } + return $errors; + } + ); + + return $errors; + } +} diff --git a/app/Services/Saml.php b/app/Services/Saml.php new file mode 100644 index 0000000000..0c321f6457 --- /dev/null +++ b/app/Services/Saml.php @@ -0,0 +1,487 @@ + + * + * @since 5.0.0 + */ +class Saml +{ + const DATA_SESSION_KEY = '_samlData'; + + /** + * OneLogin_Saml2_Auth instance. + * + * @var OneLogin\Saml2\Auth + */ + private $_auth; + + /** + * if SAML is enabled and has valid settings. + * + * @var bool + */ + private $_enabled = false; + + /** + * Settings to be passed to OneLogin_Saml2_Auth. + * + * @var array + */ + private $_settings = []; + + /** + * User attributes data. + * + * @var array + */ + private $_attributes = []; + + /** + * User attributes data with FriendlyName index. + * + * @var array + */ + private $_attributesWithFriendlyName = []; + + /** + * NameID + * + * @var string + */ + private $_nameid; + + /** + * NameID Format + * + * @var string + */ + private $_nameidFormat; + + /** + * NameID NameQualifier + * + * @var string + */ + private $_nameidNameQualifier; + + /** + * NameID SP NameQualifier + * + * @var string + */ + private $_nameidSPNameQualifier; + + /** + * If user is authenticated. + * + * @var bool + */ + private $_authenticated = false; + + /** + * SessionIndex. When the user is logged, this stored it + * from the AuthnStatement of the SAML Response + * + * @var string + */ + private $_sessionIndex; + + /** + * SessionNotOnOrAfter. When the user is logged, this stored it + * from the AuthnStatement of the SAML Response + * + * @var int|null + */ + private $_sessionExpiration; + + /** + * Initializes the SAML service and builds the OneLogin_Saml2_Auth instance. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @throws Exception + * @throws Error + */ + function __construct() + { + $this->loadSettings(); + + if ($this->isEnabled()) { + $this->loadDataFromSession(); + } else { + $this->clearData(); + } + + try { + $this->_auth = new OneLogin_Saml2_Auth($this->_settings); + } catch (Exception $e) { + $this->_enabled = false; + } + } + + /** + * Builds settings from Snipe-IT for OneLogin_Saml2_Auth. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return void + */ + private function loadSettings() + { + $setting = Setting::getSettings(); + $settings = []; + + $this->_enabled = $setting->saml_enabled == '1'; + + if ($this->isEnabled()) { + data_set($settings, 'sp.entityId', url('/')); + data_set($settings, 'sp.assertionConsumerService.url', route('saml.acs')); + data_set($settings, 'sp.singleLogoutService.url', route('saml.sls')); + data_set($settings, 'sp.x509cert', $setting->saml_sp_x509cert); + data_set($settings, 'sp.privateKey', $setting->saml_sp_privatekey); + + if (!empty(data_get($settings, 'sp.privateKey'))) { + data_set($settings, 'security.logoutRequestSigned', true); + data_set($settings, 'security.logoutResponseSigned', true); + } + + $idpMetadata = $setting->saml_idp_metadata; + if (!empty($idpMetadata)) { + $updatedAt = $setting->updated_at->timestamp; + $metadataCache = Cache::get('saml_idp_metadata_cache'); + try { + $url = null; + $metadataInfo = null; + + if (empty($metadataCache) || $metadataCache['updated_at'] != $updatedAt) { + if (filter_var($idpMetadata, FILTER_VALIDATE_URL)) { + $url = $idpMetadata; + $metadataInfo = OneLogin_Saml2_IdPMetadataParser::parseRemoteXML($idpMetadata); + } else { + $metadataInfo = OneLogin_Saml2_IdPMetadataParser::parseXML($idpMetadata); + } + + Cache::put('saml_idp_metadata_cache', [ + 'updated_at' => $updatedAt, + 'url' => $url, + 'metadata_info' => $metadataInfo, + ]); + } else { + $metadataInfo = $metadataCache['metadata_info']; + } + + $settings = OneLogin_Saml2_IdPMetadataParser::injectIntoSettings($settings, $metadataInfo); + } catch (Exception $e) { + } + } + + $custom_settings = preg_split('/\r\n|\r|\n/', $setting->saml_custom_settings); + if ($custom_settings){ + foreach($custom_settings as $custom_setting) { + $split = explode('=', $custom_setting, 2); + + if (count($split) == 2) { + $boolValue = filter_var($split[1], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + + if (!is_null($boolValue)) { + $split[1] = $boolValue; + } + + data_set($settings, $split[0], $split[1]); + } + } + } + + $this->_settings = $settings; + } + } + + /** + * Load SAML data from Session. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return void + */ + private function loadDataFromSession() { + $samlData = collect(session(self::DATA_SESSION_KEY)); + $this->_authenticated = !$samlData->isEmpty(); + $this->_nameid = $samlData->get('nameId'); + $this->_nameidFormat = $samlData->get('nameIdFormat'); + $this->_nameidNameQualifier = $samlData->get('nameIdNameQualifier'); + $this->_nameidSPNameQualifier = $samlData->get('nameIdSPNameQualifier'); + $this->_sessionIndex = $samlData->get('sessionIndex'); + $this->_sessionExpiration = $samlData->get('sessionExpiration'); + $this->_attributes = $samlData->get('attributes'); + $this->_attributesWithFriendlyName = $samlData->get('attributesWithFriendlyName'); + } + + /** + * Save SAML data to Session. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param string $data + * + * @return void + */ + private function saveDataToSession($data) + { + return session([self::DATA_SESSION_KEY => $data]); + } + + /** + * Check to see if SAML is enabled and has valid settings. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return bool + */ + public function isEnabled() + { + return $this->_enabled; + } + + /** + * Clear SAML data from session. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return void + */ + public function clearData() + { + Session::forget(self::DATA_SESSION_KEY); + $this->loadDataFromSession(); + } + + /** + * Find user from SAML data. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @param string $data + * + * @return \App\Models\User + */ + public function samlLogin($data) { + $setting = Setting::getSettings(); + $this->saveDataToSession($data); + $this->loadDataFromSession(); + + $username = $this->getUsername(); + + return User::where('username', '=', $username)->whereNull('deleted_at')->where('activated', '=', '1')->first(); + } + + /** + * Returns the OneLogin_Saml2_Auth instance. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return OneLogin\Saml2\Auth + */ + public function getAuth() { + if (!$this->isEnabled()) { + throw new HttpException(403, 'SAML not enabled.'); + } + + return $this->_auth; + } + + /** + * Gets the SP metadata. The XML representation. + * + * @param bool $alwaysPublishEncryptionCert When 'true', the returned + * metadata will always include an 'encryption' KeyDescriptor. Otherwise, + * the 'encryption' KeyDescriptor will only be included if + * $advancedSettings['security']['wantNameIdEncrypted'] or + * $advancedSettings['security']['wantAssertionsEncrypted'] are enabled. + * @param int|null $validUntil Metadata's valid time + * @param int|null $cacheDuration Duration of the cache in seconds + * + * @return string SP metadata (xml) + */ + public function getSPMetadata($alwaysPublishEncryptionCert = false, $validUntil = null, $cacheDuration = null) + { + try { + $settings = new OneLogin_Saml2_Settings($this->_settings , true); + $metadata = $settings->getSPMetadata($alwaysPublishEncryptionCert, $validUntil, $cacheDuration); + + return $metadata; + } catch (Exception $e) { + return ""; + } + } + + /** + * Extract data from SAML Response. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return array + */ + public function extractData() + { + $auth = $this->getAuth(); + return [ + 'attributes' => $auth->getAttributes(), + 'attributesWithFriendlyName' => $auth->getAttributesWithFriendlyName(), + 'nameId' => $auth->getNameId(), + 'nameIdFormat' => $auth->getNameIdFormat(), + 'nameIdNameQualifier' => $auth->getNameIdNameQualifier(), + 'nameIdSPNameQualifier' => $auth->getNameIdSPNameQualifier(), + 'sessionIndex' => $auth->getSessionIndex(), + 'sessionExpiration' => $auth->getSessionExpiration(), + ]; + } + + /** + * Checks if the user is authenticated or not. + * + * @return bool True if the user is authenticated + */ + public function isAuthenticated() + { + return $this->_authenticated; + } + + /** + * Returns the set of SAML attributes. + * + * @return array Attributes of the user. + */ + public function getAttributes() + { + return $this->_attributes; + } + + /** + * Returns the set of SAML attributes indexed by FriendlyName + * + * @return array Attributes of the user. + */ + public function getAttributesWithFriendlyName() + { + return $this->_attributesWithFriendlyName; + } + + /** + * Returns the nameID + * + * @return string The nameID of the assertion + */ + public function getNameId() + { + return $this->_nameid; + } + + /** + * Returns the nameID Format + * + * @return string The nameID Format of the assertion + */ + public function getNameIdFormat() + { + return $this->_nameidFormat; + } + + /** + * Returns the nameID NameQualifier + * + * @return string The nameID NameQualifier of the assertion + */ + public function getNameIdNameQualifier() + { + return $this->_nameidNameQualifier; + } + + /** + * Returns the nameID SP NameQualifier + * + * @return string The nameID SP NameQualifier of the assertion + */ + public function getNameIdSPNameQualifier() + { + return $this->_nameidSPNameQualifier; + } + + /** + * Returns the SessionIndex + * + * @return string|null The SessionIndex of the assertion + */ + public function getSessionIndex() + { + return $this->_sessionIndex; + } + + /** + * Returns the SessionNotOnOrAfter + * + * @return int|null The SessionNotOnOrAfter of the assertion + */ + public function getSessionExpiration() + { + return $this->_sessionExpiration; + } + + /** + * Returns the correct username from SAML Response. + * + * @author Johnson Yi + * + * @since 5.0.0 + * + * @return string + */ + public function getUsername() + { + $setting = Setting::getSettings(); + $username = $this->getNameId(); + + if (!empty($setting->saml_attr_mapping_username)) + { + $attributes = $this->getAttributes(); + + if (isset($attributes[$setting->saml_attr_mapping_username])) { + $username = $attributes[$setting->saml_attr_mapping_username][0]; + } + } + + return $username; + } +} \ No newline at end of file diff --git a/bower.json b/bower.json deleted file mode 100644 index 08dbac10f8..0000000000 --- a/bower.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "bower.json", - "description": "Bower file for Snipe-IT", - "main": "", - "authors": [ - "snipe " - ], - "license": "MIT", - "homepage": "https://github.com/snipe/snipe-it", - "private": true, - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "dependencies": { - "bootstrap-sass": "bootstrap-sass-official#^3.3.7", - "jquery-ui": "^1.12.1", - "jquery-slimscroll": "slimscroll#^1.3.8", - "bootstrap-less": "^3.3.4", - "select2": "^4.0.3", - "bootstrap-colorpicker": "^2.4.0", - "bootstrap-table": "^1.11.0", - "bootstrap-datepicker": "^1.6.4", - "iCheck": "jquery-icheck#^1.0.2", - "ekko-lightbox": "^5.0.0", - "jquery.iframe-transport": "^1.0.1", - "fastclick": "^1.0.6", - "blueimp-file-upload": "fileupload#^9.14.2", - "font-awesome": "fontawesome#^4.7.0" - } -} diff --git a/codeception.yml b/codeception.yml index 43d70c38f4..1a9a9a6c2a 100644 --- a/codeception.yml +++ b/codeception.yml @@ -5,8 +5,8 @@ paths: data: tests/_data support: tests/_support envs: tests/_envs -settings: bootstrap: _bootstrap.php +settings: colors: true memory_limit: 1024M extensions: diff --git a/composer.json b/composer.json index bebde48570..5e0e818e24 100644 --- a/composer.json +++ b/composer.json @@ -1,91 +1,115 @@ { "name": "snipe/snipe-it", "description": "Open source asset management system built on Laravel.", - "keywords": ["assets", "asset-management", "laravel"], + "keywords": [ + "assets", + "asset-management", + "it-tools", + "inventory", + "laravel" + ], "license": "AGPL-3.0-or-later", "type": "project", - "require": { - "php": ">=7.1.2", + "require": { + "php": "^7.2", + "ext-curl": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-pdo": "*", + "adldap2/adldap2": "^10.2", + "bacon/bacon-qr-code": "^1.0", "barryvdh/laravel-cors": "^0.11.3", "barryvdh/laravel-debugbar": "^3.2", - "doctrine/cache": "^1.8", - "doctrine/common": "^2.10", - "doctrine/dbal": "2.9.0", + "doctrine/cache": "^1.10", + "doctrine/common": "^2.12", + "doctrine/dbal": "^2.10", "doctrine/inflector": "^1.3", - "doctrine/instantiator": "^1.2", + "doctrine/instantiator": "^1.3", "eduardokum/laravel-mail-auto-embed": "^1.0", "enshrined/svg-sanitize": "^0.13.3", "erusev/parsedown": "^1.7", - "fideloper/proxy": "^4.1", - "guzzlehttp/guzzle": "^6.3", - "intervention/image": "^2.4", + "fideloper/proxy": "^4.3", + "guzzlehttp/guzzle": "^6.5", + "intervention/image": "^2.5", "javiereguiluz/easyslugger": "^1.0", - "laravel/framework": "5.5.*", - "laravel/passport": "4.*", - "laravel/tinker": "^1.0", - "laravelcollective/html": "^5.5", - "league/csv": "^9.2", - "alek13/slack": "^1.7", + "laravel/framework": "^6.0", + "laravel/helpers": "^1.2", + "laravel/passport": "^8.4", + "laravel/slack-notification-channel": "^2.0", + "laravel/tinker": "^2.4", + "laravelcollective/html": "^6.0", + "league/csv": "^9.5", + "league/flysystem-aws-s3-v3": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "maknz/slack": "^1.7", "neitanod/forceutf8": "^2.0", + "nesbot/carbon": "^2.32", + "onelogin/php-saml": "^3.4", + "paragonie/constant_time_encoding": "^2.3", "patchwork/utf8": "^1.3", - "phpdocumentor/reflection-docblock": "^4.0", - "phpspec/prophecy": "^1.8", - "pragmarx/google2fa": "^5.0", - "pragmarx/google2fa-laravel": "^1.0", - "predis/predis": "^1.1", - "rollbar/rollbar-laravel": "2.*", - "schuppo/password-strength": "~1.5", - "spatie/laravel-backup": "^5.12", + "phpdocumentor/reflection-docblock": "^5.1", + "phpspec/prophecy": "^1.10", + "pragmarx/google2fa-laravel": "^1.3", + "rollbar/rollbar-laravel": "^6.0", + "spatie/laravel-backup": "^6.9", "tecnickcom/tc-lib-barcode": "^1.15", - "tightenco/ziggy": "^0.7.1", + "tightenco/ziggy": "^0.9.0", "unicodeveloper/laravel-password": "^1.0", - "watson/validating": "^3.0" + "watson/validating": "^4.0" }, - "require-dev": { - "codeception/codeception": "2.3.6", - "filp/whoops": "~2.0", - "fzaninotto/faker": "1.9.1", - "phpunit/php-token-stream": "1.4.11", - "phpunit/phpunit": "~6.0", - "roave/security-advisories": "dev-master", - "squizlabs/php_codesniffer": "*", - "symfony/css-selector": "3.1.*", - "symfony/dom-crawler": "3.1.*" + "require-dev": { + "codeception/codeception": "^4.1", + "codeception/module-asserts": "^1.2", + "codeception/module-laravel5": "^1.1", + "codeception/module-rest": "^1.2", + "codeception/module-webdriver": "^1.0", + "fzaninotto/faker": "^1.9", + "phpunit/php-token-stream": "^3.1", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5", + "symfony/css-selector": "^4.4", + "symfony/dom-crawler": "^4.4" }, - "autoload": { - "classmap": [ - "database" - ], - "psr-4": { - "App\\": "app/" - } - }, - "autoload-dev": { - "classmap": [ - "tests/TestCase.php", - "tests/unit/BaseTest.php" - ] - }, - "scripts": { - "post-root-package-install": [ - "php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "php artisan key:generate" - ], - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover" - ] - }, - "config": { - "preferred-install": "dist", - "sort-packages": true, - "optimize-autoloader": true, - "process-timeout":3000, - "platform": { - "php": "7.1.2" - } + "suggest": { + "ext-mcrypt": "For upgrading from before v5.1 this is used to re-encrypt data" + }, + "extra": { + "laravel": { + "dont-discover": [ + "rollbar/rollbar-laravel" + ] } - + }, + "autoload": { + "classmap": [ + "database" + ], + "psr-4": { + "App\\": "app/" + } + }, + "autoload-dev": { + "classmap": [ + "tests/TestCase.php", + "tests/unit/BaseTest.php" + ] + }, + "scripts": { + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump" + ], + "post-create-project-cmd": [ + "php artisan key:generate" + ] + }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "optimize-autoloader": true, + "process-timeout": 3000, + "platform": { + "php": "7.2" + } + } } diff --git a/composer.lock b/composer.lock index 599e60d2b1..5f627c56bb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,63 +4,66 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "18fc9f5b8ff3febdd48f2ac48fe224bd", + "content-hash": "3fe8a441e49d1299687346810b350e00", "packages": [ { - "name": "alek13/slack", - "version": "1.11.0", + "name": "adldap2/adldap2", + "version": "v10.2.3", "source": { "type": "git", - "url": "https://github.com/php-slack/slack.git", - "reference": "31986931965edb811d61998e3b9d787976857ac1" + "url": "https://github.com/Adldap2/Adldap2.git", + "reference": "2baffac2dfef308f0a94afa360b6a77540730fd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-slack/slack/zipball/31986931965edb811d61998e3b9d787976857ac1", - "reference": "31986931965edb811d61998e3b9d787976857ac1", + "url": "https://api.github.com/repos/Adldap2/Adldap2/zipball/2baffac2dfef308f0a94afa360b6a77540730fd2", + "reference": "2baffac2dfef308f0a94afa360b6a77540730fd2", "shasum": "" }, "require": { "ext-json": "*", - "ext-mbstring": "*", - "guzzlehttp/guzzle": "~6.0|~5.0|~4.0", - "php": "^5.6|^7.0" + "ext-ldap": "*", + "illuminate/contracts": "~5.0|~6.0|~7.0", + "php": ">=7.0", + "psr/log": "~1.0", + "psr/simple-cache": "~1.0", + "tightenco/collect": "~5.0|~6.0|~7.0" }, "require-dev": { - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "4.2.*" + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~6.0" + }, + "suggest": { + "ext-fileinfo": "fileinfo is required when retrieving user encoded thumbnails" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, "autoload": { "psr-4": { - "Maknz\\Slack\\": "src/" + "Adldap\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "MIT" ], "authors": [ { - "name": "maknz", - "email": "github@mak.geek.nz" - }, - { - "name": "Alexander Chibrikin", - "email": "alek13.me@gmail.com" + "name": "Steve Bauman", + "email": "steven_bauman@outlook.com", + "role": "Developer" } ], - "description": "A simple PHP package (fork of maknz/slack) for sending messages to Slack, with a focus on ease of use and elegant syntax.", + "description": "A PHP LDAP Package for humans.", "keywords": [ - "laravel", - "slack" + "active directory", + "ad", + "adLDAP", + "adldap2", + "directory", + "ldap", + "windows" ], - "time": "2020-03-25T20:40:37+00:00" + "time": "2020-03-08T23:04:47+00:00" }, { "name": "asm89/stack-cors", @@ -115,36 +118,117 @@ "time": "2019-12-24T22:41:47+00:00" }, { - "name": "bacon/bacon-qr-code", - "version": "2.0.0", + "name": "aws/aws-sdk-php", + "version": "3.135.1", "source": { "type": "git", - "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0" + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/eaac909da3ccc32b748a65b127acd8918f58d9b0", - "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", + "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", "shasum": "" }, "require": { - "dasprid/enum": "^1.0", - "ext-iconv": "*", - "php": "^7.1" + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4.1", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" }, "require-dev": { - "phly/keep-a-changelog": "^1.4", - "phpunit/phpunit": "^6.4", - "squizlabs/php_codesniffer": "^3.1" + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" }, "suggest": { - "ext-imagick": "to generate QR code images" + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "time": "2020-04-21T18:14:29+00:00" + }, + { + "name": "bacon/bacon-qr-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "suggest": { + "ext-gd": "to generate QR code images" }, "type": "library", "autoload": { - "psr-4": { - "BaconQrCode\\": "src/" + "psr-0": { + "BaconQrCode": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -161,7 +245,7 @@ ], "description": "BaconQrCode is a QR code generator for PHP.", "homepage": "https://github.com/Bacon/BaconQrCode", - "time": "2018-04-25T17:53:56+00:00" + "time": "2017-10-17T09:59:25+00:00" }, { "name": "barryvdh/laravel-cors", @@ -227,16 +311,16 @@ }, { "name": "barryvdh/laravel-debugbar", - "version": "v3.3.3", + "version": "v3.3.2", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5" + "reference": "95c31aab33689cd4572d27038186886f4bfa63ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/57f2219f6d9efe41ed1bc880d86701c52f261bf5", - "reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/95c31aab33689cd4572d27038186886f4bfa63ae", + "reference": "95c31aab33689cd4572d27038186886f4bfa63ae", "shasum": "" }, "require": { @@ -291,55 +375,7 @@ "profiler", "webprofiler" ], - "funding": [ - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2020-05-05T10:53:32+00:00" - }, - { - "name": "dasprid/enum", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/DASPRiD/Enum.git", - "reference": "631ef6e638e9494b0310837fa531bedd908fc22b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/631ef6e638e9494b0310837fa531bedd908fc22b", - "reference": "631ef6e638e9494b0310837fa531bedd908fc22b", - "shasum": "" - }, - "require-dev": { - "phpunit/phpunit": "^6.4", - "squizlabs/php_codesniffer": "^3.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DASPRiD\\Enum\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "https://dasprids.de/" - } - ], - "description": "PHP 7.1 enum implementation", - "keywords": [ - "enum", - "map" - ], - "time": "2017-10-25T22:45:27+00:00" + "time": "2020-04-16T20:19:40+00:00" }, { "name": "defuse/php-encryption", @@ -590,34 +626,36 @@ }, { "name": "doctrine/collections", - "version": "v1.5.0", + "version": "1.6.4", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1.3" }, "require-dev": { - "doctrine/coding-standard": "~0.1@dev", - "phpunit/phpunit": "^5.7" + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0", + "vimeo/psalm": "^3.2.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Collections\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" } }, "notification-url": "https://packagist.org/downloads/", @@ -625,6 +663,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -633,10 +675,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -646,14 +684,15 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Collections Abstraction library", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", "keywords": [ "array", "collections", - "iterator" + "iterators", + "php" ], - "time": "2017-07-22T10:37:32+00:00" + "time": "2019-11-13T13:07:11+00:00" }, { "name": "doctrine/common", @@ -740,31 +779,32 @@ }, { "name": "doctrine/dbal", - "version": "v2.9.0", + "version": "2.10.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "21fdabe2fc01e004e1966f200d900554876bc63c" + "reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/21fdabe2fc01e004e1966f200d900554876bc63c", - "reference": "21fdabe2fc01e004e1966f200d900554876bc63c", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/aab745e7b6b2de3b47019da81e7225e14dcfdac8", + "reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.1" + "php": "^7.2" }, "require-dev": { - "doctrine/coding-standard": "^5.0", - "jetbrains/phpstorm-stubs": "^2018.1.2", - "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.4", - "symfony/console": "^2.0.5|^3.0|^4.0", - "symfony/phpunit-bridge": "^3.4.5|^4.0.5" + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "nikic/php-parser": "^4.4", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.4.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "vimeo/psalm": "^3.11" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -775,7 +815,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.9.x-dev", + "dev-master": "2.10.x-dev", "dev-develop": "3.0.x-dev" } }, @@ -789,6 +829,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -797,10 +841,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -811,14 +851,25 @@ "keywords": [ "abstraction", "database", + "db2", "dbal", + "mariadb", + "mssql", "mysql", - "persistence", + "oci8", + "oracle", + "pdo", "pgsql", - "php", - "queryobject" + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" ], - "time": "2018-12-04T04:39:48+00:00" + "time": "2020-04-20T17:19:26+00:00" }, { "name": "doctrine/event-manager", @@ -1021,28 +1072,30 @@ }, { "name": "doctrine/lexer", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2" }, "require-dev": { - "phpunit/phpunit": "^4.5" + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1055,14 +1108,14 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" @@ -1077,7 +1130,7 @@ "parser", "php" ], - "time": "2019-06-08T11:03:04+00:00" + "time": "2019-10-30T14:39:59+00:00" }, { "name": "doctrine/persistence", @@ -1254,6 +1307,60 @@ ], "time": "2020-03-27T11:06:43+00:00" }, + { + "name": "dragonmantank/cron-expression", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "72b6fbf76adb3cf5bc0db68559b33d41219aba27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/72b6fbf76adb3cf5bc0db68559b33d41219aba27", + "reference": "72b6fbf76adb3cf5bc0db68559b33d41219aba27", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2019-03-31T00:38:28+00:00" + }, { "name": "eduardokum/laravel-mail-auto-embed", "version": "1.0.5", @@ -1821,96 +1928,6 @@ ], "time": "2019-11-02T09:15:47+00:00" }, - { - "name": "jakub-onderka/php-console-color", - "version": "v0.2", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "1.0", - "jakub-onderka/php-parallel-lint": "1.0", - "jakub-onderka/php-var-dump-check": "0.*", - "phpunit/phpunit": "~4.3", - "squizlabs/php_codesniffer": "1.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleColor\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "jakub.onderka@gmail.com" - } - ], - "abandoned": "php-parallel-lint/php-console-color", - "time": "2018-09-29T17:23:10+00:00" - }, - { - "name": "jakub-onderka/php-console-highlighter", - "version": "v0.4", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "jakub-onderka/php-console-color": "~0.2", - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "~1.0", - "jakub-onderka/php-parallel-lint": "~1.0", - "jakub-onderka/php-var-dump-check": "~0.1", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleHighlighter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "acci@acci.cz", - "homepage": "http://www.acci.cz/" - } - ], - "description": "Highlight PHP code in terminal", - "abandoned": "php-parallel-lint/php-console-highlighter", - "time": "2018-09-29T18:48:56+00:00" - }, { "name": "javiereguiluz/easyslugger", "version": "v1.0.0", @@ -1942,88 +1959,185 @@ "time": "2015-04-12T19:57:10+00:00" }, { - "name": "kylekatarnls/update-helper", - "version": "1.2.1", + "name": "laminas/laminas-diactoros", + "version": "2.2.3", "source": { "type": "git", - "url": "https://github.com/kylekatarnls/update-helper.git", - "reference": "429be50660ed8a196e0798e5939760f168ec8ce9" + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "b596c7141f5093aefec94cb5e8745212299e290f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/429be50660ed8a196e0798e5939760f168ec8ce9", - "reference": "429be50660ed8a196e0798e5939760f168ec8ce9", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/b596c7141f5093aefec94cb5e8745212299e290f", + "reference": "b596c7141f5093aefec94cb5e8745212299e290f", "shasum": "" }, "require": { - "composer-plugin-api": "^1.1.0 || ^2.0.0", - "php": ">=5.3.0" + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.1", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "replace": { + "zendframework/zend-diactoros": "^2.2.1" }, "require-dev": { - "codeclimate/php-test-reporter": "dev-master", - "composer/composer": "2.0.x-dev || ^2.0.0-dev", - "phpunit/phpunit": ">=4.8.35 <6.0" + "ext-curl": "*", + "ext-dom": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.5.0", + "laminas/laminas-coding-standard": "~1.0.0", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5.18" }, - "type": "composer-plugin", + "type": "library", "extra": { - "class": "UpdateHelper\\ComposerPlugin" + "branch-alias": { + "dev-master": "2.1.x-dev", + "dev-develop": "2.2.x-dev", + "dev-release-1.8": "1.8.x-dev" + } }, "autoload": { - "psr-0": { - "UpdateHelper\\": "src/" + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "authors": [ - { - "name": "Kyle", - "email": "kylekatarnls@gmail.com" - } + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-7" ], - "description": "Update helper", - "time": "2020-04-07T20:44:10+00:00" + "time": "2020-03-29T12:30:54+00:00" }, { - "name": "laravel/framework", - "version": "v5.5.49", + "name": "laminas/laminas-zendframework-bridge", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/laravel/framework.git", - "reference": "a81f23d0ccd2fefa7fa9b79649ab23811631d9bf" + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "bfbbdb6c998d50dbf69d2187cb78a5f1fa36e1e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/a81f23d0ccd2fefa7fa9b79649ab23811631d9bf", - "reference": "a81f23d0ccd2fefa7fa9b79649ab23811631d9bf", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/bfbbdb6c998d50dbf69d2187cb78a5f1fa36e1e9", + "reference": "bfbbdb6c998d50dbf69d2187cb78a5f1fa36e1e9", "shasum": "" }, "require": { - "doctrine/inflector": "~1.1", - "erusev/parsedown": "~1.7", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev", + "dev-develop": "1.1.x-dev" + }, + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "time": "2020-04-03T16:01:00+00:00" + }, + { + "name": "laravel/framework", + "version": "v6.18.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "9177744ccdd8d5db970fdff2383fe89c2e94aabe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/9177744ccdd8d5db970fdff2383fe89c2e94aabe", + "reference": "9177744ccdd8d5db970fdff2383fe89c2e94aabe", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.1", + "dragonmantank/cron-expression": "^2.0", + "egulias/email-validator": "^2.1.10", + "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", + "league/commonmark": "^1.3", "league/flysystem": "^1.0.8", - "monolog/monolog": "~1.12", - "mtdowling/cron-expression": "~1.0", - "nesbot/carbon": "^1.26.0", - "php": ">=7.0", - "psr/container": "~1.0", + "monolog/monolog": "^1.12|^2.0", + "nesbot/carbon": "^2.0", + "opis/closure": "^3.1", + "php": "^7.2", + "psr/container": "^1.0", "psr/simple-cache": "^1.0", - "ramsey/uuid": "~3.0", - "swiftmailer/swiftmailer": "~6.0", - "symfony/console": "~3.3", - "symfony/debug": "~3.3", - "symfony/finder": "~3.3", - "symfony/http-foundation": "~3.3", - "symfony/http-kernel": "~3.3", - "symfony/process": "~3.3", - "symfony/routing": "~3.3", - "symfony/var-dumper": "~3.3", - "tijsverkoyen/css-to-inline-styles": "~2.2", - "vlucas/phpdotenv": "~2.2" + "ramsey/uuid": "^3.7", + "swiftmailer/swiftmailer": "^6.0", + "symfony/console": "^4.3.4", + "symfony/debug": "^4.3.4", + "symfony/finder": "^4.3.4", + "symfony/http-foundation": "^4.3.4", + "symfony/http-kernel": "^4.3.4", + "symfony/process": "^4.3.4", + "symfony/routing": "^4.3.4", + "symfony/var-dumper": "^4.3.4", + "tijsverkoyen/css-to-inline-styles": "^2.2.1", + "vlucas/phpdotenv": "^3.3" + }, + "conflict": { + "tightenco/collect": "<5.5.33" }, "replace": { "illuminate/auth": "self.version", @@ -2053,44 +2167,50 @@ "illuminate/support": "self.version", "illuminate/translation": "self.version", "illuminate/validation": "self.version", - "illuminate/view": "self.version", - "tightenco/collect": "<5.5.33" + "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "~3.0", - "doctrine/dbal": "~2.5", - "filp/whoops": "^2.1.4", - "mockery/mockery": "~1.0", - "orchestra/testbench-core": "3.5.*", - "pda/pheanstalk": "~3.0", - "phpunit/phpunit": "~6.0", + "aws/aws-sdk-php": "^3.0", + "doctrine/dbal": "^2.6", + "filp/whoops": "^2.4", + "guzzlehttp/guzzle": "^6.3|^7.0", + "league/flysystem-cached-adapter": "^1.0", + "mockery/mockery": "^1.3.1", + "moontoast/math": "^1.1", + "orchestra/testbench-core": "^4.0", + "pda/pheanstalk": "^4.0", + "phpunit/phpunit": "^7.5.15|^8.4|^9.0", "predis/predis": "^1.1.1", - "symfony/css-selector": "~3.3", - "symfony/dom-crawler": "~3.3" + "symfony/cache": "^4.3.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.5).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", - "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", - "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).", - "laravel/tinker": "Required to use the tinker console command (~1.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", - "league/flysystem-cached-adapter": "Required to use Flysystem caching (~1.0).", - "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", - "nexmo/client": "Required to use the Nexmo transport (~1.0).", - "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", - "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", - "symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.3).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.3).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", + "filp/whoops": "Required for friendly error pages in development (^2.4).", + "fzaninotto/faker": "Required to use the eloquent factory builder (^1.9.1).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.0|^7.0).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "moontoast/math": "Required to use ordered UUIDs (^1.1).", + "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^4.3.4).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^1.2).", + "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.x-dev" } }, "autoload": { @@ -2118,47 +2238,104 @@ "framework", "laravel" ], - "time": "2020-04-14T14:17:19+00:00" + "time": "2020-04-21T18:53:10+00:00" }, { - "name": "laravel/passport", - "version": "v4.0.3", + "name": "laravel/helpers", + "version": "v1.2.0", "source": { "type": "git", - "url": "https://github.com/laravel/passport.git", - "reference": "0542f1f82edfbf857d0197c34a3d41f549aff30a" + "url": "https://github.com/laravel/helpers.git", + "reference": "1f978fc5dad9f7f906b18242c654252615201de4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/passport/zipball/0542f1f82edfbf857d0197c34a3d41f549aff30a", - "reference": "0542f1f82edfbf857d0197c34a3d41f549aff30a", + "url": "https://api.github.com/repos/laravel/helpers/zipball/1f978fc5dad9f7f906b18242c654252615201de4", + "reference": "1f978fc5dad9f7f906b18242c654252615201de4", "shasum": "" }, "require": { - "firebase/php-jwt": "~3.0|~4.0|~5.0", - "guzzlehttp/guzzle": "~6.0", - "illuminate/auth": "~5.4", - "illuminate/console": "~5.4", - "illuminate/container": "~5.4", - "illuminate/contracts": "~5.4", - "illuminate/database": "~5.4", - "illuminate/encryption": "~5.4", - "illuminate/http": "~5.4", - "illuminate/support": "~5.4", - "league/oauth2-server": "^6.0", - "php": ">=5.6.4", - "phpseclib/phpseclib": "^2.0", - "symfony/psr-http-message-bridge": "~1.0", - "zendframework/zend-diactoros": "~1.0" + "illuminate/support": "~5.8.0|^6.0|^7.0", + "php": ">=7.1.3" }, "require-dev": { - "mockery/mockery": "~0.9", - "phpunit/phpunit": "~5.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Dries Vints", + "email": "dries.vints@gmail.com" + } + ], + "description": "Provides backwards compatibility for helpers in the latest Laravel release.", + "keywords": [ + "helpers", + "laravel" + ], + "time": "2020-03-03T13:52:16+00:00" + }, + { + "name": "laravel/passport", + "version": "v8.4.4", + "source": { + "type": "git", + "url": "https://github.com/laravel/passport.git", + "reference": "dd4b1d96eb1fe556a6eb2c55c942360364aa02c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/passport/zipball/dd4b1d96eb1fe556a6eb2c55c942360364aa02c1", + "reference": "dd4b1d96eb1fe556a6eb2c55c942360364aa02c1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "firebase/php-jwt": "^3.0|^4.0|^5.0", + "guzzlehttp/guzzle": "^6.0", + "illuminate/auth": "^6.0|^7.0", + "illuminate/console": "^6.0|^7.0", + "illuminate/container": "^6.0|^7.0", + "illuminate/contracts": "^6.0|^7.0", + "illuminate/cookie": "^6.0|^7.0", + "illuminate/database": "^6.0|^7.0", + "illuminate/encryption": "^6.0|^7.0", + "illuminate/http": "^6.0|^7.0", + "illuminate/support": "^6.0|^7.0", + "laminas/laminas-diactoros": "^2.2", + "league/oauth2-server": "^8.0", + "nyholm/psr7": "^1.0", + "php": "^7.2", + "phpseclib/phpseclib": "^2.0", + "symfony/psr-http-message-bridge": "^2.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.4|^5.0", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" }, "laravel": { "providers": [ @@ -2187,40 +2364,98 @@ "oauth", "passport" ], - "time": "2017-09-24T14:21:39+00:00" + "time": "2020-04-21T19:24:59+00:00" }, { - "name": "laravel/tinker", - "version": "v1.0.10", + "name": "laravel/slack-notification-channel", + "version": "v2.0.2", "source": { "type": "git", - "url": "https://github.com/laravel/tinker.git", - "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7" + "url": "https://github.com/laravel/slack-notification-channel.git", + "reference": "ecc90a70791195d6f5e20b2732a5eb1eb9619d10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/ad571aacbac1539c30d480908f9d0c9614eaf1a7", - "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7", + "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/ecc90a70791195d6f5e20b2732a5eb1eb9619d10", + "reference": "ecc90a70791195d6f5e20b2732a5eb1eb9619d10", "shasum": "" }, "require": { - "illuminate/console": "~5.1|^6.0", - "illuminate/contracts": "~5.1|^6.0", - "illuminate/support": "~5.1|^6.0", - "php": ">=5.5.9", - "psy/psysh": "0.7.*|0.8.*|0.9.*", - "symfony/var-dumper": "~3.0|~4.0" + "guzzlehttp/guzzle": "^6.0", + "illuminate/notifications": "~5.8.0|^6.0|^7.0", + "php": "^7.1.3" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" - }, - "suggest": { - "illuminate/database": "The Illuminate Database package (~5.1)." + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\SlackChannelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Notifications\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Slack Notification Channel for laravel.", + "keywords": [ + "laravel", + "notifications", + "slack" + ], + "time": "2019-08-27T14:40:26+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "cde90a7335a2130a4488beb68f4b2141869241db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/cde90a7335a2130a4488beb68f4b2141869241db", + "reference": "cde90a7335a2130a4488beb68f4b2141869241db", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0", + "illuminate/contracts": "^6.0|^7.0|^8.0", + "illuminate/support": "^6.0|^7.0|^8.0", + "php": "^7.2", + "psy/psysh": "^0.10.3", + "symfony/var-dumper": "^4.3|^5.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.1", + "phpunit/phpunit": "^8.4|^9.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" }, "laravel": { "providers": [ @@ -2250,39 +2485,39 @@ "laravel", "psysh" ], - "time": "2019-08-07T15:10:45+00:00" + "time": "2020-04-07T15:01:31+00:00" }, { "name": "laravelcollective/html", - "version": "v5.5.4", + "version": "v6.0.3", "source": { "type": "git", "url": "https://github.com/LaravelCollective/html.git", - "reference": "04c596a69975b901f2223eb6eb4adf55354121c2" + "reference": "bcc317d21a7e04eebcc81c4109fa84feaab63590" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/LaravelCollective/html/zipball/04c596a69975b901f2223eb6eb4adf55354121c2", - "reference": "04c596a69975b901f2223eb6eb4adf55354121c2", + "url": "https://api.github.com/repos/LaravelCollective/html/zipball/bcc317d21a7e04eebcc81c4109fa84feaab63590", + "reference": "bcc317d21a7e04eebcc81c4109fa84feaab63590", "shasum": "" }, "require": { - "illuminate/http": "5.5.*", - "illuminate/routing": "5.5.*", - "illuminate/session": "5.5.*", - "illuminate/support": "5.5.*", - "illuminate/view": "5.5.*", - "php": ">=7.0.0" + "illuminate/http": "^6.0", + "illuminate/routing": "^6.0", + "illuminate/session": "^6.0", + "illuminate/support": "^6.0", + "illuminate/view": "^6.0", + "php": ">=7.2" }, "require-dev": { - "illuminate/database": "5.5.*", - "mockery/mockery": "~0.9.4", - "phpunit/phpunit": "~5.4" + "illuminate/database": "^6.0", + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.0-dev" }, "laravel": { "providers": [ @@ -2307,18 +2542,18 @@ "MIT" ], "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - }, { "name": "Adam Engebretson", "email": "adam@laravelcollective.com" + }, + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" } ], "description": "HTML and Form Builders for the Laravel Framework", "homepage": "https://laravelcollective.com", - "time": "2018-03-24T00:39:21+00:00" + "time": "2019-10-02T00:37:39+00:00" }, { "name": "lcobucci/jwt", @@ -2375,6 +2610,80 @@ ], "time": "2019-05-24T18:30:49+00:00" }, + { + "name": "league/commonmark", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "c995966d35424bae20f76f8b31248099487a3f57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c995966d35424bae20f76f8b31248099487a3f57", + "reference": "c995966d35424bae20f76f8b31248099487a3f57", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1" + }, + "conflict": { + "scrutinizer/ocular": "1.7.*" + }, + "require-dev": { + "cebe/markdown": "~1.0", + "commonmark/commonmark.js": "0.29.1", + "erusev/parsedown": "~1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "~1.4", + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" + }, + "bin": [ + "bin/commonmark" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "time": "2020-04-20T13:36:51+00:00" + }, { "name": "league/csv", "version": "9.5.0", @@ -2576,44 +2885,135 @@ "sftp", "storage" ], - "funding": [ - { - "url": "https://offset.earth/frankdejonge", - "type": "other" - } - ], "time": "2020-04-16T13:21:26+00:00" }, { - "name": "league/oauth2-server", - "version": "6.1.1", + "name": "league/flysystem-aws-s3-v3", + "version": "1.0.24", "source": { "type": "git", - "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "a0cabb573c7cd5ee01803daec992d6ee3677c4ae" + "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", + "reference": "4382036bde5dc926f9b8b337e5bdb15e5ec7b570" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/a0cabb573c7cd5ee01803daec992d6ee3677c4ae", - "reference": "a0cabb573c7cd5ee01803daec992d6ee3677c4ae", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/4382036bde5dc926f9b8b337e5bdb15e5ec7b570", + "reference": "4382036bde5dc926f9b8b337e5bdb15e5ec7b570", "shasum": "" }, "require": { - "defuse/php-encryption": "^2.1", + "aws/aws-sdk-php": "^3.0.0", + "league/flysystem": "^1.0.40", + "php": ">=5.5.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "^2.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\AwsS3v3\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Flysystem adapter for the AWS S3 SDK v3.x", + "time": "2020-02-23T13:31:58+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/08ef74e9be88100807a3b92cc9048a312bf01d6f", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "time": "2018-07-09T20:51:04+00:00" + }, + { + "name": "league/oauth2-server", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git", + "reference": "e1dc4d708c56fcfa205be4bb1862b6d525b4baac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/e1dc4d708c56fcfa205be4bb1862b6d525b4baac", + "reference": "e1dc4d708c56fcfa205be4bb1862b6d525b4baac", + "shasum": "" + }, + "require": { + "defuse/php-encryption": "^2.2.1", + "ext-json": "*", "ext-openssl": "*", - "lcobucci/jwt": "^3.1", - "league/event": "^2.1", - "paragonie/random_compat": "^2.0", - "php": ">=5.6.0", - "psr/http-message": "^1.0" + "lcobucci/jwt": "^3.3.1", + "league/event": "^2.2", + "php": ">=7.1.0", + "psr/http-message": "^1.0.1" }, "replace": { "league/oauth2server": "*", "lncd/oauth2": "*" }, "require-dev": { - "phpunit/phpunit": "^4.8.38 || ^5.7.21", - "zendframework/zend-diactoros": "^1.0" + "phpstan/phpstan": "^0.11.8", + "phpstan/phpstan-phpunit": "^0.11.2", + "phpunit/phpunit": "^7.5.13 || ^8.2.3", + "roave/security-advisories": "dev-master", + "zendframework/zend-diactoros": "^2.1.2" }, "type": "library", "autoload": { @@ -2631,6 +3031,12 @@ "email": "hello@alexbilbie.com", "homepage": "http://www.alexbilbie.com", "role": "Developer" + }, + { + "name": "Andy Millington", + "email": "andrew@noexceptions.io", + "homepage": "https://www.noexceptions.io", + "role": "Developer" } ], "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", @@ -2650,7 +3056,56 @@ "secure", "server" ], - "time": "2017-12-23T23:33:42+00:00" + "time": "2019-07-13T18:58:26+00:00" + }, + { + "name": "maknz/slack", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/maknz/slack.git", + "reference": "7f21fefc70c76b304adc1b3a780c8740dfcfb595" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maknz/slack/zipball/7f21fefc70c76b304adc1b3a780c8740dfcfb595", + "reference": "7f21fefc70c76b304adc1b3a780c8740dfcfb595", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "guzzlehttp/guzzle": "~6.0|~5.0|~4.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "4.2.*" + }, + "suggest": { + "illuminate/support": "Required for Laravel support" + }, + "type": "library", + "autoload": { + "psr-4": { + "Maknz\\Slack\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "maknz", + "email": "github@mak.geek.nz" + } + ], + "description": "A simple PHP package for sending messages to Slack, with a focus on ease of use and elegant syntax. Includes Laravel support out of the box.", + "keywords": [ + "laravel", + "slack" + ], + "time": "2015-06-03T03:35:16+00:00" }, { "name": "masterminds/html5", @@ -2721,16 +3176,16 @@ }, { "name": "maximebf/debugbar", - "version": "v1.16.3", + "version": "v1.16.2", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372" + "reference": "40f375504a4dd8e59f779c3f3cac524777ddcde5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/1a1605b8e9bacb34cc0c6278206d699772e1d372", - "reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/40f375504a4dd8e59f779c3f3cac524777ddcde5", + "reference": "40f375504a4dd8e59f779c3f3cac524777ddcde5", "shasum": "" }, "require": { @@ -2778,25 +3233,25 @@ "debug", "debugbar" ], - "time": "2020-05-06T07:06:27+00:00" + "time": "2020-04-16T09:05:52+00:00" }, { "name": "monolog/monolog", - "version": "1.25.3", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c861fcba2ca29404dc9e617eedd9eff4616986b8", + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": "^7.2", + "psr/log": "^1.0.1" }, "provide": { "psr/log-implementation": "1.0.0" @@ -2804,33 +3259,36 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", + "elasticsearch/elasticsearch": "^6.0", + "graylog2/gelf-php": "^1.4.2", + "jakub-onderka/php-parallel-lint": "^0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", + "phpspec/prophecy": "^1.6.1", + "phpunit/phpunit": "^8.3", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -2856,33 +3314,46 @@ "logging", "psr-3" ], - "time": "2019-12-20T14:15:16+00:00" + "time": "2019-12-20T14:22:59+00:00" }, { - "name": "mtdowling/cron-expression", - "version": "v1.2.3", + "name": "mtdowling/jmespath.php", + "version": "2.5.0", "source": { "type": "git", - "url": "https://github.com/mtdowling/cron-expression.git", - "reference": "9be552eebcc1ceec9776378f7dcc085246cacca6" + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "52168cb9472de06979613d365c7f1ab8798be895" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9be552eebcc1ceec9776378f7dcc085246cacca6", - "reference": "9be552eebcc1ceec9776378f7dcc085246cacca6", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", + "reference": "52168cb9472de06979613d365c7f1ab8798be895", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "^1.4" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "composer/xdebug-handler": "^1.2", + "phpunit/phpunit": "^4.8.36|^7.5.15" }, + "bin": [ + "bin/jp.php" + ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, "autoload": { "psr-4": { - "Cron\\": "src/Cron/" - } + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2895,13 +3366,12 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "description": "Declaratively specify how to extract elements from a JSON document", "keywords": [ - "cron", - "schedule" + "json", + "jsonpath" ], - "abandoned": "dragonmantank/cron-expression", - "time": "2019-12-28T04:23:06+00:00" + "time": "2019-12-30T18:03:34+00:00" }, { "name": "neitanod/forceutf8", @@ -2942,34 +3412,40 @@ }, { "name": "nesbot/carbon", - "version": "1.39.1", + "version": "2.32.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33" + "reference": "f10e22cf546704fab1db4ad4b9dedbc5c797a0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4be0c005164249208ce1b5ca633cd57bdd42ff33", - "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f10e22cf546704fab1db4ad4b9dedbc5c797a0dc", + "reference": "f10e22cf546704fab1db4ad4b9dedbc5c797a0dc", "shasum": "" }, "require": { - "kylekatarnls/update-helper": "^1.1", - "php": ">=5.3.9", - "symfony/translation": "~2.6 || ~3.0 || ~4.0" + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { - "composer/composer": "^1.2", - "friendsofphp/php-cs-fixer": "~2", - "phpunit/phpunit": "^4.8.35 || ^5.7" + "doctrine/orm": "^2.7", + "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", + "kylekatarnls/multi-tester": "^1.1", + "phpmd/phpmd": "^2.8", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "^7.5 || ^8.0", + "squizlabs/php_codesniffer": "^3.4" }, "bin": [ - "bin/upgrade-carbon" + "bin/carbon" ], "type": "library", "extra": { - "update-helper": "Carbon\\Upgrade", + "branch-alias": { + "dev-master": "2.x-dev" + }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -2978,7 +3454,7 @@ }, "autoload": { "psr-4": { - "": "src/" + "Carbon\\": "src/Carbon/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2990,16 +3466,20 @@ "name": "Brian Nesbitt", "email": "brian@nesbot.com", "homepage": "http://nesbot.com" + }, + { + "name": "kylekatarnls", + "homepage": "http://github.com/kylekatarnls" } ], - "description": "A simple API extension for DateTime.", + "description": "An API extension for DateTime that supports 281 different languages.", "homepage": "http://carbon.nesbot.com", "keywords": [ "date", "datetime", "time" ], - "time": "2019-10-14T05:51:36+00:00" + "time": "2020-03-31T13:43:19+00:00" }, { "name": "nikic/php-parser", @@ -3053,6 +3533,179 @@ ], "time": "2020-04-10T16:34:50+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/55ff6b76573f5b242554c9775792bd59fb52e11c", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c", + "shasum": "" + }, + "require": { + "php": "^7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "dev-master", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "time": "2019-09-05T13:24:16+00:00" + }, + { + "name": "onelogin/php-saml", + "version": "3.4.1", + "source": { + "type": "git", + "url": "https://github.com/onelogin/php-saml.git", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/onelogin/php-saml/zipball/5fbf3486704ac9835b68184023ab54862c95f213", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "robrichards/xmlseclibs": ">=3.0.4" + }, + "require-dev": { + "pdepend/pdepend": "^2.5.0", + "php-coveralls/php-coveralls": "^1.0.2 || ^2.0", + "phploc/phploc": "^2.1 || ^3.0 || ^4.0", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1", + "sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0", + "squizlabs/php_codesniffer": "^3.1.1" + }, + "suggest": { + "ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs", + "ext-gettext": "Install gettext and php5-gettext libs to handle translations", + "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)" + }, + "type": "library", + "autoload": { + "psr-4": { + "OneLogin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "OneLogin PHP SAML Toolkit", + "homepage": "https://developers.onelogin.com/saml/php", + "keywords": [ + "SAML2", + "onelogin", + "saml" + ], + "time": "2019-11-25T17:30:07+00:00" + }, + { + "name": "opis/closure", + "version": "3.5.1", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/93ebc5712cdad8d5f489b500c59d122df2e53969", + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "time": "2019-11-29T22:36:02+00:00" + }, { "name": "paragonie/constant_time_encoding", "version": "v2.3.0", @@ -3117,33 +3770,29 @@ }, { "name": "paragonie/random_compat", - "version": "v2.0.18", + "version": "v9.99.99", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db" + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", - "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", "shasum": "" }, "require": { - "php": ">=5.2.0" + "php": "^7" }, "require-dev": { - "phpunit/phpunit": "4.*|5.*" + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" }, "suggest": { "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -3162,7 +3811,7 @@ "pseudorandom", "random" ], - "time": "2019-01-03T20:59:08+00:00" + "time": "2018-07-02T15:55:56+00:00" }, { "name": "patchwork/utf8", @@ -3227,22 +3876,75 @@ "time": "2019-12-03T14:44:12+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "2.1.0", + "name": "php-http/message-factory", + "version": "v1.0.2", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b" + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b", - "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "time": "2015-12-19T14:08:53+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { "php": ">=7.1" }, + "require-dev": { + "phpunit/phpunit": "~6" + }, "type": "library", "extra": { "branch-alias": { @@ -3273,45 +3975,42 @@ "reflection", "static analysis" ], - "time": "2020-04-27T09:25:28+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.4", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpdocumentor/type-resolver": "0.4.*", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -3322,33 +4021,36 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-28T18:55:12+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.2", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "ext-tokenizer": "^7.2", + "mockery/mockery": "~1" }, "type": "library", "extra": { @@ -3372,7 +4074,62 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "time": "2020-02-18T18:59:58+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2020-03-21T18:07:53+00:00" }, { "name": "phpseclib/phpseclib", @@ -3531,38 +4288,30 @@ }, { "name": "pragmarx/google2fa", - "version": "v5.0.0", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4" + "reference": "26c4c5cf30a2844ba121760fd7301f8ad240100b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/17c969c82f427dd916afe4be50bafc6299aef1b4", - "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/26c4c5cf30a2844ba121760fd7301f8ad240100b", + "reference": "26c4c5cf30a2844ba121760fd7301f8ad240100b", "shasum": "" }, "require": { - "paragonie/constant_time_encoding": "~1.0|~2.0", - "paragonie/random_compat": ">=1", - "php": ">=5.4", - "symfony/polyfill-php56": "~1.2" + "paragonie/constant_time_encoding": "^1.0|^2.0", + "php": "^7.1|^8.0" }, "require-dev": { - "phpunit/phpunit": "~4|~5|~6" + "phpstan/phpstan": "^0.12.18", + "phpunit/phpunit": "^7.5.15|^8.5|^9.0" }, "type": "library", - "extra": { - "component": "package", - "branch-alias": { - "dev-master": "2.0-dev" - } - }, "autoload": { "psr-4": { - "PragmaRX\\Google2FA\\": "src/", - "PragmaRX\\Google2FA\\Tests\\": "tests/" + "PragmaRX\\Google2FA\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3583,7 +4332,7 @@ "Two Factor Authentication", "google2fa" ], - "time": "2019-03-19T22:44:16+00:00" + "time": "2020-04-05T10:47:18+00:00" }, { "name": "pragmarx/google2fa-laravel", @@ -3715,33 +4464,31 @@ "time": "2019-03-20T16:42:58+00:00" }, { - "name": "predis/predis", - "version": "v1.1.1", + "name": "psr/cache", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/nrk/predis.git", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", "shasum": "" }, "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + "php": ">=5.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Predis\\": "src/" + "Psr\\Cache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3750,19 +4497,17 @@ ], "authors": [ { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Flexible and feature-complete Redis client for PHP and HHVM", - "homepage": "http://github.com/nrk/predis", + "description": "Common interface for caching libraries", "keywords": [ - "nosql", - "predis", - "redis" + "cache", + "psr", + "psr-6" ], - "time": "2016-06-16T16:22:20+00:00" + "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", @@ -3813,6 +4558,58 @@ ], "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -3960,32 +4757,30 @@ }, { "name": "psy/psysh", - "version": "v0.9.12", + "version": "v0.10.3", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "90da7f37568aee36b116a030c5f99c915267edd4" + "reference": "2bde2fa03e05dff0aee834598b951d6fc7c6fe02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/90da7f37568aee36b116a030c5f99c915267edd4", - "reference": "90da7f37568aee36b116a030c5f99c915267edd4", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/2bde2fa03e05dff0aee834598b951d6fc7c6fe02", + "reference": "2bde2fa03e05dff0aee834598b951d6fc7c6fe02", "shasum": "" }, "require": { "dnoegel/php-xdg-base-dir": "0.1.*", "ext-json": "*", "ext-tokenizer": "*", - "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", - "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", - "php": ">=5.4.0", - "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0", - "symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0" + "nikic/php-parser": "~4.0|~3.0|~2.0|~1.3", + "php": "^8.0 || ^7.0 || ^5.5.9", + "symfony/console": "~5.0|~4.0|~3.0|^2.4.2|~2.3.10", + "symfony/var-dumper": "~5.0|~4.0|~3.0|~2.7" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.2", - "hoa/console": "~2.15|~3.16", - "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" + "hoa/console": "3.17.*" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", @@ -4000,7 +4795,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-develop": "0.9.x-dev" + "dev-master": "0.10.x-dev" } }, "autoload": { @@ -4030,7 +4825,7 @@ "interactive", "shell" ], - "time": "2019-12-06T14:19:43+00:00" + "time": "2020-04-07T06:44:48+00:00" }, { "name": "ralouphie/getallheaders", @@ -4160,22 +4955,60 @@ "time": "2020-02-21T04:36:14+00:00" }, { - "name": "rollbar/rollbar", - "version": "v1.8.1", + "name": "robrichards/xmlseclibs", + "version": "3.1.0", "source": { "type": "git", - "url": "https://github.com/rollbar/rollbar-php.git", - "reference": "8a57ad9574d85bd818eaedfc8049fdcb16795f31" + "url": "https://github.com/robrichards/xmlseclibs.git", + "reference": "8d8e56ca7914440a8c60caff1a865e7dff1d9a5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rollbar/rollbar-php/zipball/8a57ad9574d85bd818eaedfc8049fdcb16795f31", - "reference": "8a57ad9574d85bd818eaedfc8049fdcb16795f31", + "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/8d8e56ca7914440a8c60caff1a865e7dff1d9a5a", + "reference": "8d8e56ca7914440a8c60caff1a865e7dff1d9a5a", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">= 5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "RobRichards\\XMLSecLibs\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "A PHP library for XML Security", + "homepage": "https://github.com/robrichards/xmlseclibs", + "keywords": [ + "security", + "signature", + "xml", + "xmldsig" + ], + "time": "2020-04-22T17:19:51+00:00" + }, + { + "name": "rollbar/rollbar", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/rollbar/rollbar-php.git", + "reference": "245670b32d8e6072d6b364eda242f245879cdee9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rollbar/rollbar-php/zipball/245670b32d8e6072d6b364eda242f245879cdee9", + "reference": "245670b32d8e6072d6b364eda242f245879cdee9", "shasum": "" }, "require": { "ext-curl": "*", - "monolog/monolog": "^1", + "monolog/monolog": "^1 || ^2", "psr/log": "^1" }, "require-dev": { @@ -4183,7 +5016,7 @@ "mockery/mockery": "0.9.*", "packfire/php5.3-compat": "*", "phpmd/phpmd": "@stable", - "phpunit/phpunit": "4.8.*", + "phpunit/phpunit": "4.8.* || ^5", "squizlabs/php_codesniffer": "2.*" }, "suggest": { @@ -4216,33 +5049,33 @@ "logging", "monitoring" ], - "time": "2019-05-06T11:31:11+00:00" + "time": "2019-10-02T06:24:31+00:00" }, { "name": "rollbar/rollbar-laravel", - "version": "v2.4.3", + "version": "v6.0.0", "source": { "type": "git", "url": "https://github.com/rollbar/rollbar-php-laravel.git", - "reference": "e581cd9a175d0b3fa0568893026e38c1d94329b2" + "reference": "11df7e19313a4cf60769d26ce35e29b09d5405cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rollbar/rollbar-php-laravel/zipball/e581cd9a175d0b3fa0568893026e38c1d94329b2", - "reference": "e581cd9a175d0b3fa0568893026e38c1d94329b2", + "url": "https://api.github.com/repos/rollbar/rollbar-php-laravel/zipball/11df7e19313a4cf60769d26ce35e29b09d5405cd", + "reference": "11df7e19313a4cf60769d26ce35e29b09d5405cd", "shasum": "" }, "require": { - "illuminate/support": "^4.0|^5.0", - "php": ">=5.4", - "rollbar/rollbar": "^1" + "illuminate/support": "^6.0|^7.0", + "php": ">=7.2", + "rollbar/rollbar": "^2" }, "require-dev": { - "mockery/mockery": "^0.9", - "orchestra/testbench": "~3.0", - "phpunit/phpunit": "~4.0|~5.0", - "satooshi/php-coveralls": "^1.0", - "squizlabs/php_codesniffer": "2.*" + "mockery/mockery": "^1", + "orchestra/testbench": "^4|^5", + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^8", + "squizlabs/php_codesniffer": "3.*" }, "type": "library", "extra": { @@ -4284,91 +5117,34 @@ "monitoring", "rollbar" ], - "time": "2019-01-01T22:20:05+00:00" - }, - { - "name": "schuppo/password-strength", - "version": "v1.13", - "source": { - "type": "git", - "url": "https://github.com/schuppo/PasswordStrengthPackage.git", - "reference": "b1deef216f27461d7184ae5f136cec7ec821bc3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schuppo/PasswordStrengthPackage/zipball/b1deef216f27461d7184ae5f136cec7ec821bc3e", - "reference": "b1deef216f27461d7184ae5f136cec7ec821bc3e", - "shasum": "" - }, - "require": { - "illuminate/support": "~5.0|6.*", - "illuminate/translation": "^5.1|6.*", - "php": ">=5.4.0" - }, - "require-dev": { - "illuminate/validation": "~5.0|6.*", - "phpunit/phpunit": "^4.8" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Schuppo\\PasswordStrength\\PasswordStrengthServiceProvider" - ] - } - }, - "autoload": { - "psr-0": { - "Schuppo\\PasswordStrength": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Oliver Schupp", - "email": "oliver.schupp@yahoo.de" - } - ], - "description": "This package provides a validator for ensuring strong passwords in Laravel 4 applications.", - "keywords": [ - "laravel", - "laravel 5", - "laravel5", - "password", - "password strength", - "validation" - ], - "time": "2020-02-24T12:17:19+00:00" + "time": "2020-03-03T20:09:19+00:00" }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -4405,32 +5181,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -4455,9 +5232,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/exporter", @@ -4581,24 +5361,24 @@ }, { "name": "spatie/db-dumper", - "version": "2.13.1", + "version": "2.16.0", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "8f88e6f772ddf6c5a71ec9c0b5682ebca3323377" + "reference": "7c6d3b7f7191e1549aa5996b8ab371de31eec762" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/8f88e6f772ddf6c5a71ec9c0b5682ebca3323377", - "reference": "8f88e6f772ddf6c5a71ec9c0b5682ebca3323377", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/7c6d3b7f7191e1549aa5996b8ab371de31eec762", + "reference": "7c6d3b7f7191e1549aa5996b8ab371de31eec762", "shasum": "" }, "require": { - "php": "^7.0", - "symfony/process": "^3.0|^4.0" + "php": "^7.2", + "symfony/process": "^4.2|^5.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0|^8.0" }, "type": "library", "autoload": { @@ -4627,42 +5407,44 @@ "mysqldump", "spatie" ], - "time": "2019-03-01T15:46:17+00:00" + "time": "2020-04-16T15:10:19+00:00" }, { "name": "spatie/laravel-backup", - "version": "5.12.1", + "version": "6.9.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-backup.git", - "reference": "553562557ef13fda0e823cc609cd7d4f2c4f2552" + "reference": "d92ff3a676755f6184a59053f99ca5fe45710c8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/553562557ef13fda0e823cc609cd7d4f2c4f2552", - "reference": "553562557ef13fda0e823cc609cd7d4f2c4f2552", + "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/d92ff3a676755f6184a59053f99ca5fe45710c8d", + "reference": "d92ff3a676755f6184a59053f99ca5fe45710c8d", "shasum": "" }, "require": { - "illuminate/console": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "illuminate/contracts": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "illuminate/events": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "illuminate/filesystem": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "illuminate/notifications": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "illuminate/support": "~5.5.0|~5.6.0|~5.7.0|~5.8.0", - "league/flysystem": "^1.0.27", - "php": "^7.1", - "spatie/db-dumper": "^2.11.1", + "illuminate/console": "^5.8.15|^6.0|^7.0", + "illuminate/contracts": "^5.8.15|^6.0|^7.0", + "illuminate/events": "^5.8.15|^6.0|^7.0", + "illuminate/filesystem": "^5.8.15|^6.0|^7.0", + "illuminate/notifications": "^5.8.15|^6.0|^7.0", + "illuminate/support": "^5.8.15|^6.0|^7.0", + "league/flysystem": "^1.0.49", + "php": "^7.2", + "spatie/db-dumper": "^2.12", "spatie/temporary-directory": "^1.1", - "symfony/finder": "^3.3|^4.0" + "symfony/finder": "^4.2|^5.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "orchestra/testbench": "~3.5.0|~3.6.0|~3.7.0|~3.8.0", - "phpunit/phpunit": "^7.3" + "laravel/slack-notification-channel": "^1.0", + "league/flysystem-aws-s3-v3": "^1.0", + "mockery/mockery": "^1.3", + "orchestra/testbench": "3.8.*|4.*|5.*", + "phpunit/phpunit": "^8.4|^9.0" }, "suggest": { - "guzzlehttp/guzzle": "Allows notifications to be sent via Slack" + "laravel/slack-notification-channel": "Required for sending notifications via Slack" }, "type": "library", "extra": { @@ -4692,7 +5474,7 @@ "role": "Developer" } ], - "description": "A Laravel 5 package to backup your application", + "description": "A Laravel package to backup your application", "homepage": "https://github.com/spatie/laravel-backup", "keywords": [ "backup", @@ -4700,27 +5482,27 @@ "laravel-backup", "spatie" ], - "time": "2019-04-04T12:00:30+00:00" + "time": "2020-04-20T10:27:54+00:00" }, { "name": "spatie/temporary-directory", - "version": "1.1.5", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/spatie/temporary-directory.git", - "reference": "539d0856c5d6344619b3c5ab472e1ff6c655df5a" + "reference": "fcb127e615700751dac2aefee0ea2808ff3f5bb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/539d0856c5d6344619b3c5ab472e1ff6c655df5a", - "reference": "539d0856c5d6344619b3c5ab472e1ff6c655df5a", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/fcb127e615700751dac2aefee0ea2808ff3f5bb1", + "reference": "fcb127e615700751dac2aefee0ea2808ff3f5bb1", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.2" }, "require-dev": { - "phpunit/phpunit": "^6.3" + "phpunit/phpunit": "^8.0" }, "type": "library", "autoload": { @@ -4746,7 +5528,7 @@ "spatie", "temporary-directory" ], - "time": "2019-07-16T20:39:53+00:00" + "time": "2019-12-15T18:52:09+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -4863,25 +5645,28 @@ }, { "name": "symfony/console", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "bf60d5e606cd595391c5f82bf6b570d9573fa120" + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/bf60d5e606cd595391c5f82bf6b570d9573fa120", - "reference": "bf60d5e606cd595391c5f82bf6b570d9573fa120", + "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" }, "conflict": { "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", "symfony/process": "<3.3" }, "provide": { @@ -4889,11 +5674,12 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { "psr/log": "For using the console logger", @@ -4904,7 +5690,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4931,43 +5717,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-03-27T17:07:22+00:00" + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/css-selector", - "version": "v3.1.10", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d" + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d", - "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/afc26133a6fbdd4f8842e38893e0ee4685c7c94b", + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4983,14 +5755,14 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -4998,36 +5770,50 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2017-01-02T20:31:54+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/debug", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29" + "reference": "346636d2cae417992ecfd761979b2ab98b339a45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29", - "reference": "ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29", + "url": "https://api.github.com/repos/symfony/debug/zipball/346636d2cae417992ecfd761979b2ab98b339a45", + "reference": "346636d2cae417992ecfd761979b2ab98b339a45", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/log": "~1.0" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5068,34 +5854,97 @@ "type": "tidelift" } ], - "time": "2020-03-23T10:22:40+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.40", + "name": "symfony/error-handler", + "version": "v4.4.7", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "9d4e22943b73acc1ba50595b7de1a01fe9dbad48" + "url": "https://github.com/symfony/error-handler.git", + "reference": "7e9828fc98aa1cf27b422fe478a84f5b0abb7358" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9d4e22943b73acc1ba50595b7de1a01fe9dbad48", - "reference": "9d4e22943b73acc1ba50595b7de1a01fe9dbad48", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/7e9828fc98aa1cf27b422fe478a84f5b0abb7358", + "reference": "7e9828fc98aa1cf27b422fe478a84f5b0abb7358", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3", + "psr/log": "~1.0", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2020-03-30T14:07:33+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -5104,7 +5953,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5145,29 +5994,87 @@ "type": "tidelift" } ], - "time": "2020-03-15T09:38:08+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { - "name": "symfony/finder", - "version": "v3.4.40", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/5ec813ccafa8164ef21757e8c725d3a57da59200", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "5729f943f9854c5781984ed4907bbb817735776b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/5729f943f9854c5781984ed4907bbb817735776b", + "reference": "5729f943f9854c5781984ed4907bbb817735776b", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" } }, "autoload": { @@ -5194,34 +6101,49 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-02-14T07:34:21+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "eded33daef1147be7ff1249706be9a49fe2c7a44" + "reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/eded33daef1147be7ff1249706be9a49fe2c7a44", - "reference": "eded33daef1147be7ff1249706be9a49fe2c7a44", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/62f92509c9abfd1f73e17b8cf1b72c0bdac6611b", + "reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": "^7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5248,49 +6170,37 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-18T20:23:17+00:00" + "time": "2020-03-30T14:07:33+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "139d477cc926de9ca03c3d59b51ab6e22450c6df" + "reference": "f356a489e51856b99908005eb7f2c51a1dfc95dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/139d477cc926de9ca03c3d59b51ab6e22450c6df", - "reference": "139d477cc926de9ca03c3d59b51ab6e22450c6df", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f356a489e51856b99908005eb7f2c51a1dfc95dc", + "reference": "f356a489e51856b99908005eb7f2c51a1dfc95dc", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/log": "~1.0", - "symfony/debug": "^3.3.3|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8" + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", "twig/twig": "<1.34|<2.4,>=2" }, "provide": { @@ -5298,34 +6208,32 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5352,34 +6260,82 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-28T17:41:38+00:00" + "time": "2020-03-30T14:59:15+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.16.0", + "name": "symfony/mime", + "version": "v4.4.7", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294" + "url": "https://github.com/symfony/mime.git", + "reference": "6dde9dc70155e91b850b1d009d1f841c54bc4aba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1aab00e39cebaef4d8652497f46c15c1b7e45294", - "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294", + "url": "https://api.github.com/repos/symfony/mime/zipball/6dde9dc70155e91b850b1d009d1f841c54bc4aba", + "reference": "6dde9dc70155e91b850b1d009d1f841c54bc4aba", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-03-27T16:54:36+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", "shasum": "" }, "require": { @@ -5391,7 +6347,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -5438,20 +6394,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.16.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "d51debc1391a609c514f6f072dd59a61b461502a" + "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/d51debc1391a609c514f6f072dd59a61b461502a", - "reference": "d51debc1391a609c514f6f072dd59a61b461502a", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ad6d62792bfbcfc385dd34b424d4fcf9712a32c8", + "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8", "shasum": "" }, "require": { @@ -5463,7 +6419,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -5511,20 +6467,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.16.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "ab0af41deab94ec8dceb3d1fb408bdd038eba4dc" + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ab0af41deab94ec8dceb3d1fb408bdd038eba4dc", - "reference": "ab0af41deab94ec8dceb3d1fb408bdd038eba4dc", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", "shasum": "" }, "require": { @@ -5538,7 +6494,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -5587,20 +6543,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.16.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "a54881ec0ab3b2005c406aed0023c062879031e7" + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a54881ec0ab3b2005c406aed0023c062879031e7", - "reference": "a54881ec0ab3b2005c406aed0023c062879031e7", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", "shasum": "" }, "require": { @@ -5612,7 +6568,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -5660,163 +6616,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" - }, - { - "name": "symfony/polyfill-php56", - "version": "v1.16.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "14b55b0e88c67c6a14526799abaea197dde78911" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/14b55b0e88c67c6a14526799abaea197dde78911", - "reference": "14b55b0e88c67c6a14526799abaea197dde78911", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/polyfill-util": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.16-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php56\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-05-08T16:50:20+00:00" - }, - { - "name": "symfony/polyfill-php70", - "version": "v1.16.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6cc55bd2a085dbe05b4122c1987a82897b8da419" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6cc55bd2a085dbe05b4122c1987a82897b8da419", - "reference": "6cc55bd2a085dbe05b4122c1987a82897b8da419", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.16-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-05-02T14:56:09+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.16.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "42fda6d7380e5c940d7f68341ccae89d5ab9963b" + "reference": "37b0976c78b94856543260ce09b460a7bc852747" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/42fda6d7380e5c940d7f68341ccae89d5ab9963b", - "reference": "42fda6d7380e5c940d7f68341ccae89d5ab9963b", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", + "reference": "37b0976c78b94856543260ce09b460a7bc852747", "shasum": "" }, "require": { @@ -5825,7 +6638,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -5872,20 +6685,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T17:28:34+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { - "name": "symfony/polyfill-util", - "version": "v1.16.0", + "name": "symfony/polyfill-php73", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-util.git", - "reference": "fa1fdaf94e8a60932d8821692eb1ed07efc52db2" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/fa1fdaf94e8a60932d8821692eb1ed07efc52db2", - "reference": "fa1fdaf94e8a60932d8821692eb1ed07efc52db2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", "shasum": "" }, "require": { @@ -5894,13 +6707,19 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Util\\": "" - } + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5916,12 +6735,12 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony utilities for portability of PHP codes", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "compat", "compatibility", "polyfill", + "portable", "shim" ], "funding": [ @@ -5938,29 +6757,29 @@ "type": "tidelift" } ], - "time": "2020-05-02T14:56:09+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/process", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f5104c9dcbc2cfad45d01d5150c1da9836967271" + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f5104c9dcbc2cfad45d01d5150c1da9836967271", - "reference": "f5104c9dcbc2cfad45d01d5150c1da9836967271", + "url": "https://api.github.com/repos/symfony/process/zipball/3e40e87a20eaf83a1db825e1fa5097ae89042db3", + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5987,45 +6806,30 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-12T14:33:46+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v1.2.0", + "version": "v2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad" + "reference": "ce709cd9c90872c08c2427b45739d5f3c781ab4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", - "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/ce709cd9c90872c08c2427b45739d5f3c781ab4f", + "reference": "ce709cd9c90872c08c2427b45739d5f3c781ab4f", "shasum": "" }, "require": { "php": "^7.1", "psr/http-message": "^1.0", - "symfony/http-foundation": "^3.4 || ^4.0" + "symfony/http-foundation": "^4.4 || ^5.0" }, "require-dev": { "nyholm/psr7": "^1.1", - "symfony/phpunit-bridge": "^3.4.20 || ^4.0", - "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + "symfony/phpunit-bridge": "^4.4 || ^5.0" }, "suggest": { "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" @@ -6033,7 +6837,7 @@ "type": "symfony-bridge", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -6049,13 +6853,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" } ], "description": "PSR HTTP message bridge", @@ -6066,38 +6870,38 @@ "psr-17", "psr-7" ], - "time": "2019-03-11T18:22:33+00:00" + "time": "2020-01-02T08:07:11+00:00" }, { "name": "symfony/routing", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "53b432fde8eea7dab820e75abda5b97fdaa829b4" + "reference": "0f562fa613e288d7dbae6c63abbc9b33ed75a8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/53b432fde8eea7dab820e75abda5b97fdaa829b4", - "reference": "53b432fde8eea7dab820e75abda5b97fdaa829b4", + "url": "https://api.github.com/repos/symfony/routing/zipball/0f562fa613e288d7dbae6c63abbc9b33ed75a8f8", + "reference": "0f562fa613e288d7dbae6c63abbc9b33ed75a8f8", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "conflict": { - "symfony/config": "<3.3.1", - "symfony/dependency-injection": "<3.3", + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", "symfony/yaml": "<3.4" }, "require-dev": { - "doctrine/annotations": "~1.0", + "doctrine/annotations": "~1.2", "psr/log": "~1.0", - "symfony/config": "^3.3.1|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", @@ -6109,7 +6913,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6142,54 +6946,104 @@ "uri", "url" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-12T09:58:27+00:00" + "time": "2020-03-30T11:41:10+00:00" }, { - "name": "symfony/translation", - "version": "v3.4.40", + "name": "symfony/service-contracts", + "version": "v1.1.8", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "4e844362f573713e6d45949795c95a4cb6cf760d" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/4e844362f573713e6d45949795c95a4cb6cf760d", - "reference": "4e844362f573713e6d45949795c95a4cb6cf760d", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-10-14T12:27:06+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "4e54d336f2eca5facad449d0b0118bb449375b76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/4e54d336f2eca5facad449d0b0118bb449375b76", + "reference": "4e54d336f2eca5facad449d0b0118bb449375b76", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<2.8", + "symfony/config": "<3.4", "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", "symfony/yaml": "<3.4" }, + "provide": { + "symfony/translation-implementation": "1.0" + }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/http-kernel": "~3.4|~4.0", - "symfony/intl": "^2.8.18|^3.2.5|~4.0", - "symfony/var-dumper": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -6199,7 +7053,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6226,56 +7080,106 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-12T16:39:58+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { - "name": "symfony/var-dumper", - "version": "v3.4.40", + "name": "symfony/translation-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "13c03169ae485fc7f1a5143256622ce1bd3c77eb" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "364518c132c95642e530d9b2d217acbc2ccac3e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/13c03169ae485fc7f1a5143256622ce1bd3c77eb", - "reference": "13c03169ae485fc7f1a5143256622ce1bd3c77eb", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/364518c132c95642e530d9b2d217acbc2ccac3e6", + "reference": "364518c132c95642e530d9b2d217acbc2ccac3e6", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" - }, - "require-dev": { - "ext-iconv": "*", - "twig/twig": "~1.34|~2.4" + "php": "^7.1.3" }, "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "ext-symfony_debug": "" + "symfony/translation-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T11:12:18+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "5a0c2d93006131a36cf6f767d10e2ca8333b0d4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/5a0c2d93006131a36cf6f767d10e2ca8333b0d4a", + "reference": "5a0c2d93006131a36cf6f767d10e2ca8333b0d4a", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" } }, "autoload": { @@ -6309,21 +7213,7 @@ "debug", "dump" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-03-17T22:27:36+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "tecnickcom/tc-lib-barcode", @@ -6479,25 +7369,75 @@ "time": "2020-01-02T16:01:17+00:00" }, { - "name": "tightenco/ziggy", - "version": "v0.7.1", + "name": "tightenco/collect", + "version": "v7.6.1", "source": { "type": "git", - "url": "https://github.com/tightenco/ziggy.git", - "reference": "aa4c42aaec9516da892bc2e9f6e992582646af77" + "url": "https://github.com/tightenco/collect.git", + "reference": "4b6a215656eb77bdaa31b0f61aa9e2a3eaf2f7a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tightenco/ziggy/zipball/aa4c42aaec9516da892bc2e9f6e992582646af77", - "reference": "aa4c42aaec9516da892bc2e9f6e992582646af77", + "url": "https://api.github.com/repos/tightenco/collect/zipball/4b6a215656eb77bdaa31b0f61aa9e2a3eaf2f7a0", + "reference": "4b6a215656eb77bdaa31b0f61aa9e2a3eaf2f7a0", "shasum": "" }, "require": { - "laravel/framework": "~5.4" + "php": "^7.1.3", + "symfony/var-dumper": "^3.4 || ^4.0 || ^5.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "nesbot/carbon": "^2.23.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Collect/Support/helpers.php", + "src/Collect/Support/alias.php" + ], + "psr-4": { + "Tightenco\\Collect\\": "src/Collect" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "Collect - Illuminate Collections as a separate package.", + "keywords": [ + "collection", + "laravel" + ], + "time": "2020-04-17T18:15:55+00:00" + }, + { + "name": "tightenco/ziggy", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/tightenco/ziggy.git", + "reference": "5344605c9fc2786e0d5626ad031ceafa003f700b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tightenco/ziggy/zipball/5344605c9fc2786e0d5626ad031ceafa003f700b", + "reference": "5344605c9fc2786e0d5626ad031ceafa003f700b", + "shasum": "" + }, + "require": { + "laravel/framework": ">=5.4@dev" }, "require-dev": { "mikey179/vfsstream": "^1.6", - "orchestra/testbench": "~3.6" + "orchestra/testbench": "^5.0" }, "type": "library", "extra": { @@ -6517,17 +7457,17 @@ "MIT" ], "authors": [ - { - "name": "Matt Stauffer", - "email": "matt@tighten.co" - }, { "name": "Daniel Coulbourne", "email": "daniel@tighten.co" + }, + { + "name": "Matt Stauffer", + "email": "matt@tighten.co" } ], "description": "Generates a Blade directive exporting all of your named Laravel routes. Also provides a nice route() helper function in JavaScript.", - "time": "2019-04-26T22:03:47+00:00" + "time": "2020-03-02T22:24:23+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -6640,26 +7580,27 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.6.4", + "version": "v3.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "67d472b1794c986381a8950e4958e1adb779d561" + "reference": "1b3103013797f04521c6cae5560f604649484066" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/67d472b1794c986381a8950e4958e1adb779d561", - "reference": "67d472b1794c986381a8950e4958e1adb779d561", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1b3103013797f04521c6cae5560f604649484066", + "reference": "1b3103013797f04521c6cae5560f604649484066", "shasum": "" }, "require": { - "php": "^5.3.9 || ^7.0 || ^8.0", + "php": "^5.4 || ^7.0", + "phpoption/phpoption": "^1.5", "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.35 || ^5.0" + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -6668,7 +7609,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -6698,43 +7639,33 @@ "env", "environment" ], - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2020-05-02T13:38:00+00:00" + "time": "2020-04-12T15:18:03+00:00" }, { "name": "watson/validating", - "version": "3.3.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/dwightwatson/validating.git", - "reference": "288eb177e9b3721e8e1f2dad81d4f17928a3c916" + "reference": "b8731af37eade6b25aac1fcec5e90fdfdb9de5f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dwightwatson/validating/zipball/288eb177e9b3721e8e1f2dad81d4f17928a3c916", - "reference": "288eb177e9b3721e8e1f2dad81d4f17928a3c916", + "url": "https://api.github.com/repos/dwightwatson/validating/zipball/b8731af37eade6b25aac1fcec5e90fdfdb9de5f5", + "reference": "b8731af37eade6b25aac1fcec5e90fdfdb9de5f5", "shasum": "" }, "require": { - "illuminate/contracts": ">= 5.4.0", - "illuminate/database": ">= 5.4.0", - "illuminate/events": ">= 5.4.0", - "illuminate/support": ">= 5.4.0", - "illuminate/validation": ">= 5.4.0", - "php": ">=5.6.4" + "illuminate/contracts": "~6.0", + "illuminate/database": "~6.0", + "illuminate/events": "~6.0", + "illuminate/support": "~6.0", + "illuminate/validation": "~6.0", + "php": "^7.2" }, "require-dev": { "mockery/mockery": "~1.0", - "phpunit/phpunit": "~5.0" + "phpunit/phpunit": "~8.0" }, "type": "library", "autoload": { @@ -6758,7 +7689,7 @@ "laravel", "validation" ], - "time": "2019-09-05T20:06:01+00:00" + "time": "2019-10-02T23:15:31+00:00" }, { "name": "webmozart/assert", @@ -6807,84 +7738,21 @@ "validate" ], "time": "2020-04-18T12:12:48+00:00" - }, - { - "name": "zendframework/zend-diactoros", - "version": "1.8.7", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/a85e67b86e9b8520d07e6415fcbcb8391b44a75b", - "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "psr/http-message": "^1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-dom": "*", - "ext-libxml": "*", - "php-http/psr7-integration-tests": "dev-master", - "phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7", - "zendframework/zend-coding-standard": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-release-1.8": "1.8.x-dev" - } - }, - "autoload": { - "files": [ - "src/functions/create_uploaded_file.php", - "src/functions/marshal_headers_from_sapi.php", - "src/functions/marshal_method_from_sapi.php", - "src/functions/marshal_protocol_version_from_sapi.php", - "src/functions/marshal_uri_from_sapi.php", - "src/functions/normalize_server.php", - "src/functions/normalize_uploaded_files.php", - "src/functions/parse_cookie_header.php" - ], - "psr-4": { - "Zend\\Diactoros\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "description": "PSR HTTP Message implementations", - "homepage": "https://github.com/zendframework/zend-diactoros", - "keywords": [ - "http", - "psr", - "psr-7" - ], - "abandoned": "laminas/laminas-diactoros", - "time": "2019-08-06T17:53:53+00:00" } ], "packages-dev": [ { "name": "behat/gherkin", - "version": "v4.4.5", + "version": "v4.6.2", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", "shasum": "" }, "require": { @@ -6892,8 +7760,8 @@ }, "require-dev": { "phpunit/phpunit": "~4.5|~5", - "symfony/phpunit-bridge": "~2.7|~3", - "symfony/yaml": "~2.3|~3" + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" }, "suggest": { "symfony/yaml": "If you want to parse features, represented in YAML files" @@ -6930,65 +7798,56 @@ "gherkin", "parser" ], - "time": "2016-10-30T11:50:56+00:00" + "time": "2020-03-17T14:03:26+00:00" }, { "name": "codeception/codeception", - "version": "2.3.6", + "version": "4.1.4", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "c3dd3b5d9e0b1ea6c2fcca52457736dc756716f8" + "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c3dd3b5d9e0b1ea6c2fcca52457736dc756716f8", - "reference": "c3dd3b5d9e0b1ea6c2fcca52457736dc756716f8", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/55d8d1d882fa0777e47de17b04c29b3c50fe29e7", + "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7", "shasum": "" }, "require": { - "behat/gherkin": "~4.4.0", + "behat/gherkin": "^4.4.0", + "codeception/lib-asserts": "^1.0", + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.1.1 | ^9.0", + "codeception/stub": "^2.0 | ^3.0", + "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "facebook/webdriver": ">=1.1.3 <2.0", - "guzzlehttp/guzzle": ">=4.1.4 <7.0", - "guzzlehttp/psr7": "~1.0", - "php": ">=5.4.0 <8.0", - "phpunit/php-code-coverage": ">=2.2.4 <6.0", - "phpunit/phpunit": ">4.8.20 <7.0", - "phpunit/phpunit-mock-objects": ">2.3 <5.0", - "sebastian/comparator": ">1.1 <3.0", - "sebastian/diff": ">=1.4 <3.0", - "stecman/symfony-console-completion": "^0.7.0", - "symfony/browser-kit": ">=2.7 <4.0", - "symfony/console": ">=2.7 <4.0", - "symfony/css-selector": ">=2.7 <4.0", - "symfony/dom-crawler": ">=2.7.5 <4.0", - "symfony/event-dispatcher": ">=2.7 <4.0", - "symfony/finder": ">=2.7 <4.0", - "symfony/yaml": ">=2.7 <4.0" + "guzzlehttp/psr7": "~1.4", + "php": ">=5.6.0 <8.0", + "symfony/console": ">=2.7 <6.0", + "symfony/css-selector": ">=2.7 <6.0", + "symfony/event-dispatcher": ">=2.7 <6.0", + "symfony/finder": ">=2.7 <6.0", + "symfony/yaml": ">=2.7 <6.0" }, "require-dev": { + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", "codeception/specify": "~0.3", - "facebook/graph-sdk": "~5.3", - "flow/jsonpath": "~0.2", - "league/factory-muffin": "^3.0", - "league/factory-muffin-faker": "^1.0", + "codeception/util-universalframework": "*@dev", "monolog/monolog": "~1.8", - "pda/pheanstalk": "~3.0", - "php-amqplib/php-amqplib": "~2.4", - "predis/predis": "^1.0", "squizlabs/php_codesniffer": "~2.0", - "symfony/process": ">=2.7 <4.0", - "vlucas/phpdotenv": "^2.4.0" + "symfony/process": ">=2.7 <6.0", + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" }, "suggest": { "codeception/specify": "BDD-style code blocks", "codeception/verify": "BDD-style assertions", - "flow/jsonpath": "For using JSONPath in REST module", - "league/factory-muffin": "For DataFactory module", - "league/factory-muffin-faker": "For Faker support in DataFactory module", - "phpseclib/phpseclib": "for SFTP option in FTP Module", + "hoa/console": "For interactive console functionality", + "stecman/symfony-console-completion": "For BASH autocompletion", "symfony/phpunit-bridge": "For phpunit-bridge support" }, "bin": [ @@ -7000,7 +7859,7 @@ }, "autoload": { "psr-4": { - "Codeception\\": "src\\Codeception", + "Codeception\\": "src/Codeception", "Codeception\\Extension\\": "ext" } }, @@ -7024,105 +7883,349 @@ "functional testing", "unit testing" ], - "time": "2017-09-28T23:19:49+00:00" + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], + "time": "2020-03-23T17:07:20+00:00" }, { - "name": "facebook/webdriver", - "version": "1.7.1", + "name": "codeception/lib-asserts", + "version": "1.12.0", "source": { "type": "git", - "url": "https://github.com/php-webdriver/php-webdriver-archive.git", - "reference": "e43de70f3c7166169d0f14a374505392734160e5" + "url": "https://github.com/Codeception/lib-asserts.git", + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver-archive/zipball/e43de70f3c7166169d0f14a374505392734160e5", - "reference": "e43de70f3c7166169d0f14a374505392734160e5", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/acd0dc8b394595a74b58dcc889f72569ff7d8e71", + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71", "shasum": "" }, "require": { - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-zip": "*", - "php": "^5.6 || ~7.0", - "symfony/process": "^2.8 || ^3.1 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "php-coveralls/php-coveralls": "^2.0", - "php-mock/php-mock-phpunit": "^1.1", - "phpunit/phpunit": "^5.7", - "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", - "squizlabs/php_codesniffer": "^2.6", - "symfony/var-dumper": "^3.3 || ^4.0" - }, - "suggest": { - "ext-SimpleXML": "For Firefox profile creation" + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3 | ^9.0", + "php": ">=5.6.0 <8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-community": "1.5-dev" - } - }, "autoload": { - "psr-4": { - "Facebook\\WebDriver\\": "lib/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], - "description": "A PHP client for Selenium WebDriver", - "homepage": "https://github.com/facebook/php-webdriver", + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Assertion methods used by Codeception core and Asserts module", + "homepage": "http://codeception.com/", "keywords": [ - "facebook", - "php", - "selenium", - "webdriver" + "codeception" ], - "abandoned": "php-webdriver/webdriver", - "time": "2019-06-13T08:02:18+00:00" + "time": "2020-04-17T18:20:46+00:00" }, { - "name": "filp/whoops", - "version": "2.7.2", + "name": "codeception/lib-innerbrowser", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "17d0d3f266c8f925ebd035cd36f83cf802b47d4a" + "url": "https://github.com/Codeception/lib-innerbrowser.git", + "reference": "2123542b1325cc349ac68868abe74638bcb32ab6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/17d0d3f266c8f925ebd035cd36f83cf802b47d4a", - "reference": "17d0d3f266c8f925ebd035cd36f83cf802b47d4a", + "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/2123542b1325cc349ac68868abe74638bcb32ab6", + "reference": "2123542b1325cc349ac68868abe74638bcb32ab6", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0", - "psr/log": "^1.0.1" + "codeception/codeception": "*@dev", + "php": ">=5.6.0 <8.0", + "symfony/browser-kit": ">=2.7 <6.0", + "symfony/dom-crawler": ">=2.7 <6.0" + }, + "conflict": { + "codeception/codeception": "<4.0" }, "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" + "codeception/util-universalframework": "dev-master" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } + "autoload": { + "classmap": [ + "src/" + ] }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Parent library for all Codeception framework modules and PhpBrowser", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception" + ], + "time": "2020-02-20T14:46:50+00:00" + }, + { + "name": "codeception/module-asserts", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-asserts.git", + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "shasum": "" + }, + "require": { + "codeception/codeception": "*@dev", + "codeception/lib-asserts": "^1.12.0", + "php": ">=5.6.0 <8.0" + }, + "conflict": { + "codeception/codeception": "<4.0" + }, + "require-dev": { + "codeception/util-robohelpers": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Codeception module containing various assertions", + "homepage": "http://codeception.com/", + "keywords": [ + "assertions", + "asserts", + "codeception" + ], + "time": "2020-04-20T07:26:11+00:00" + }, + { + "name": "codeception/module-laravel5", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-laravel5.git", + "reference": "419c382fde8a6b2110001fa0a206ec4cdb77c6d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-laravel5/zipball/419c382fde8a6b2110001fa0a206ec4cdb77c6d4", + "reference": "419c382fde8a6b2110001fa0a206ec4cdb77c6d4", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "codeception/lib-innerbrowser": "^1.0", + "php": ">=5.6.0 <8.0" + }, + "require-dev": { + "codeception/module-asserts": "^1.0", + "codeception/module-rest": "^1.0", + "codeception/util-robohelpers": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan-Henk Gerritsen" + }, + { + "name": "Michael Bodnarchuk" + } + ], + "description": "Codeception module for Laravel 5 framework", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception", + "laravel5" + ], + "time": "2020-03-28T14:59:53+00:00" + }, + { + "name": "codeception/module-rest", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-rest.git", + "reference": "c86417af517bb1fb5b88550455d823a7c9fc167e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-rest/zipball/c86417af517bb1fb5b88550455d823a7c9fc167e", + "reference": "c86417af517bb1fb5b88550455d823a7c9fc167e", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "flow/jsonpath": "^0.5", + "justinrainbow/json-schema": "^5.2.9", + "php": ">=5.6.0 <8.0" + }, + "require-dev": { + "codeception/lib-innerbrowser": "^1.0", + "codeception/util-robohelpers": "dev-master", + "codeception/util-universalframework": "^1.0" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "REST module for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception", + "rest" + ], + "time": "2020-02-01T19:23:56+00:00" + }, + { + "name": "codeception/module-webdriver", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-webdriver.git", + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "php": ">=5.6.0 <8.0", + "php-webdriver/webdriver": "^1.6.0" + }, + "require-dev": { + "codeception/util-robohelpers": "dev-master" + }, + "suggest": { + "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Zaahid Bateson" + } + ], + "description": "WebDriver module for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "acceptance-testing", + "browser-testing", + "codeception" + ], + "time": "2020-04-01T10:18:18+00:00" + }, + { + "name": "codeception/phpunit-wrapper", + "version": "8.1.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/phpunit-wrapper.git", + "reference": "e610200adf75ebc1ea7cf10d7cdb43e0f5fff3cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e610200adf75ebc1ea7cf10d7cdb43e0f5fff3cc", + "reference": "e610200adf75ebc1ea7cf10d7cdb43e0f5fff3cc", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "phpunit/php-code-coverage": "^7.0", + "phpunit/phpunit": "^8.0", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0" + }, + "require-dev": { + "codeception/specify": "*", + "vlucas/phpdotenv": "^3.0" + }, + "type": "library", "autoload": { "psr-4": { - "Whoops\\": "src/Whoops/" + "Codeception\\PHPUnit\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -7131,22 +8234,83 @@ ], "authors": [ { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" + "name": "Davert", + "email": "davert.php@resend.cc" } ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" + "description": "PHPUnit classes used by Codeception", + "time": "2020-04-17T18:30:51+00:00" + }, + { + "name": "codeception/stub", + "version": "3.6.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/a3ba01414cbee76a1bced9f9b6b169cc8d203880", + "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880", + "shasum": "" + }, + "require": { + "phpunit/phpunit": "^8.4 | ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "time": "2020-05-05T12:28:07+00:00" + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "time": "2020-02-07T18:42:28+00:00" + }, + { + "name": "flow/jsonpath", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/FlowCommunications/JSONPath.git", + "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/b9738858c75d008c1211612b973e9510f8b7f8ea", + "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "peekmo/jsonpath": "dev-master", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Flow\\JSONPath": "src/", + "Flow\\JSONPath\\Test": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Frank", + "email": "stephen@flowsa.com" + } + ], + "description": "JSONPath implementation for parsing, searching and flattening arrays", + "time": "2019-07-15T17:23:22+00:00" }, { "name": "fzaninotto/faker", @@ -7198,6 +8362,72 @@ ], "time": "2019-12-12T13:22:17+00:00" }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.9", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2019-09-25T14:49:45+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.9.5", @@ -7248,22 +8478,22 @@ }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -7299,20 +8529,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -7346,45 +8576,109 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { - "name": "phpunit/php-code-coverage", - "version": "5.2.2", + "name": "php-webdriver/webdriver", + "version": "1.8.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b" + "url": "https://github.com/php-webdriver/php-webdriver.git", + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8ed1902a57849e117b5651fc1a5c48110946c06b", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/polyfill-mbstring": "^1.12", + "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^1.0", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "sminnee/phpunit-mock-objects": "^3.4", + "squizlabs/php_codesniffer": "^3.5", + "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + }, + "files": [ + "lib/Exception/TimeoutException.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", + "homepage": "https://github.com/php-webdriver/php-webdriver", + "keywords": [ + "Chromedriver", + "geckodriver", + "php", + "selenium", + "webdriver" + ], + "time": "2020-03-04T14:40:12+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "7.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "ext-xdebug": "^2.5", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.2.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -7399,7 +8693,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -7410,29 +8704,32 @@ "testing", "xunit" ], - "time": "2017-08-03T12:40:43+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -7447,7 +8744,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -7457,7 +8754,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -7502,28 +8799,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -7538,7 +8835,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -7547,33 +8844,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "1.4.11", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.3.3" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -7596,57 +8893,56 @@ "keywords": [ "tokenizer" ], - "time": "2017-02-27T10:12:30+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.4.4", + "version": "8.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932" + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/562f7dc75d46510a4ed5d16189ae57fbe45a9932", - "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/67750516bc02f300e2742fed2f50177f8f37bedf", + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.2.2", - "phpunit/php-file-iterator": "^1.4.2", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^4.0.3", - "sebastian/comparator": "^2.0.2", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -7654,7 +8950,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.4.x-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -7680,345 +8976,7 @@ "testing", "xunit" ], - "time": "2017-11-08T11:26:09+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "2f789b59ab89669015ad984afa350c4ec577ade0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0", - "reference": "2f789b59ab89669015ad984afa350c4ec577ade0", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.0" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "abandoned": true, - "time": "2017-08-03T14:08:16+00:00" - }, - { - "name": "roave/security-advisories", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "ec1a75b10126327b351fdea7c2b9bfb94e2f6f35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ec1a75b10126327b351fdea7c2b9bfb94e2f6f35", - "reference": "ec1a75b10126327b351fdea7c2b9bfb94e2f6f35", - "shasum": "" - }, - "conflict": { - "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.12", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", - "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bagisto/bagisto": "<0.1.5", - "barrelstrength/sprout-base-email": "<3.9", - "bolt/bolt": "<3.6.10", - "brightlocal/phpwhois": "<=4.2.5", - "buddypress/buddypress": "<5.1.2", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<18.10.8|>=19,<19.4.5", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1-alpha.11", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.46|>=4.5,<4.8.6", - "contao/listing-bundle": ">=4,<4.4.8", - "datadog/dd-trace": ">=0.30,<0.30.2", - "david-garcia/phpwhois": "<=4.3.1", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dolibarr/dolibarr": "<=10.0.6", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4", - "drupal/drupal": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4", - "endroid/qr-code-bundle": "<3.4.2", - "enshrined/svg-sanitize": "<0.13.1", - "erusev/parsedown": "<1.7.2", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", - "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.1|>=6,<6.7.9.1|>=6.8,<6.13.6.2|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.6.2", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1", - "ezyang/htmlpurifier": "<4.1.1", - "firebase/php-jwt": "<2", - "fooman/tcpdf": "<6.2.22", - "fossar/tcpdf-parser": "<6.2.22", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7-beta.8", - "gree/jose": "<=2.2", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": ">=7,<7.1.2", - "ivankristianto/phpwhois": "<=4.3", - "james-heinrich/getid3": "<1.9.9", - "joomla/session": "<1.3.1", - "jsmitty12/phpwhois": "<5.1", - "kazist/phpwhois": "<=4.2.6", - "kreait/firebase-php": ">=3.2,<3.8.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30|>=7,<7.1.2", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "league/commonmark": "<0.18.3", - "librenms/librenms": "<1.53", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", - "monolog/monolog": ">=1.8,<1.12", - "namshi/jose": "<2.2", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", - "openid/php-openid": "<2.3", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", - "paragonie/random_compat": "<2", - "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.4", - "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6", - "phpmyadmin/phpmyadmin": "<4.9.2", - "phpoffice/phpexcel": "<1.8.2", - "phpoffice/phpspreadsheet": "<1.8", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<6.3", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/gamification": "<2.3.2", - "prestashop/ps_facetedsearch": "<3.4.1", - "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", - "propel/propel1": ">=1,<=1.7.1", - "pusher/pusher-php-server": "<2.2.1", - "robrichards/xmlseclibs": "<3.0.4", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "shopware/shopware": "<5.3.7", - "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", - "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", - "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", - "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.5|>=4.5,<4.5.2", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", - "silverstripe/subsites": ">=2,<2.1.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.18.6", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplito/elliptic-php": "<1.0.6", - "slim/slim": "<2.6", - "smarty/smarty": "<3.1.33", - "socalnick/scn-social-auth": "<1.15.2", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.29.2", - "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.49", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/resource-bundle": "<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3", - "sylius/sylius": "<1.3.16|>=1.4,<1.4.12|>=1.5,<1.5.9|>=1.6,<1.6.5", - "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/mime": ">=4.3,<4.3.8", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", - "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "tecnickcom/tcpdf": "<6.2.22", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", - "theonedemon/phpwhois": "<=4.2.5", - "titon/framework": ">=0,<9.9.99", - "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", - "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", - "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", - "ua-parser/uap-php": "<3.8", - "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", - "wallabag/tcpdf": "<6.2.22", - "willdurand/js-translation-bundle": "<2.1.1", - "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.15", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.15", - "yiisoft/yii2-elasticsearch": "<2.0.5", - "yiisoft/yii2-gii": "<2.0.4", - "yiisoft/yii2-jui": "<2.0.4", - "yiisoft/yii2-redis": "<2.0.8", - "yourls/yourls": "<1.7.4", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", - "zendframework/zend-diactoros": ">=1,<1.8.4", - "zendframework/zend-feed": ">=1,<2.10.3", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=1,<2.8.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<2.5.1", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - }, - { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", - "type": "tidelift" - } - ], - "time": "2020-05-09T00:00:21+00:00" + "time": "2020-03-31T08:52:04+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -8067,28 +9025,31 @@ }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -8113,27 +9074,30 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -8141,7 +9105,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -8164,7 +9128,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", @@ -8260,25 +9224,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -8298,7 +9262,53 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", @@ -8343,72 +9353,29 @@ "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03T07:35:21+00:00" }, - { - "name": "stecman/symfony-console-completion", - "version": "0.7.0", - "source": { - "type": "git", - "url": "https://github.com/stecman/symfony-console-completion.git", - "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/stecman/symfony-console-completion/zipball/5461d43e53092b3d3b9dbd9d999f2054730f4bbb", - "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb", - "shasum": "" - }, - "require": { - "php": ">=5.3.2", - "symfony/console": "~2.3 || ~3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Stecman\\Component\\Symfony\\Console\\BashCompletion\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Stephen Holdaway", - "email": "stephen@stecman.co.nz" - } - ], - "description": "Automatic BASH completion for Symfony Console Component based applications.", - "time": "2016-02-24T05:08:54+00:00" - }, { "name": "symfony/browser-kit", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "1c7bcd954ad1fc02354c4cfd3fcd1b0c95245367" + "reference": "e4b0dc1b100bf75b5717c5b451397f230a618a42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/1c7bcd954ad1fc02354c4cfd3fcd1b0c95245367", - "reference": "1c7bcd954ad1fc02354c4cfd3fcd1b0c95245367", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/e4b0dc1b100bf75b5717c5b451397f230a618a42", + "reference": "e4b0dc1b100bf75b5717c5b451397f230a618a42", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/dom-crawler": "~2.8|~3.0|~4.0" + "php": "^7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0" + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/process": "" @@ -8416,7 +9383,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -8457,28 +9424,33 @@ "type": "tidelift" } ], - "time": "2020-03-15T09:38:08+00:00" + "time": "2020-03-28T10:15:50+00:00" }, { "name": "symfony/dom-crawler", - "version": "v3.1.10", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "7eede2a901a19928494194f7d1815a77b9a473a0" + "reference": "4d0fb3374324071ecdd94898367a3fa4b5563162" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7eede2a901a19928494194f7d1815a77b9a473a0", - "reference": "7eede2a901a19928494194f7d1815a77b9a473a0", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4d0fb3374324071ecdd94898367a3fa4b5563162", + "reference": "4d0fb3374324071ecdd94898367a3fa4b5563162", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, + "conflict": { + "masterminds/html5": "<2.6" + }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/css-selector": "" @@ -8486,7 +9458,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -8513,31 +9485,45 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2017-01-21T17:13:55+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-29T19:12:22+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.40", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "8fef49ac1357f4e05c997a1f139467ccb186bffa" + "reference": "ef166890d821518106da3560086bfcbeb4fadfec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8fef49ac1357f4e05c997a1f139467ccb186bffa", - "reference": "8fef49ac1357f4e05c997a1f139467ccb186bffa", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ef166890d821518106da3560086bfcbeb4fadfec", + "reference": "ef166890d821518106da3560086bfcbeb4fadfec", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "~3.4|~4.0" + "symfony/console": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -8545,7 +9531,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -8572,21 +9558,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-04-24T10:16:04+00:00" + "time": "2020-03-30T11:41:10+00:00" }, { "name": "theseer/tokenizer", @@ -8631,17 +9603,20 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "roave/security-advisories": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.1.2" + "php": "^7.2", + "ext-curl": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-pdo": "*" }, "platform-dev": [], "platform-overrides": { - "php": "7.1.2" + "php": "7.2" }, "plugin-api-version": "1.1.0" } diff --git a/config/app.php b/config/app.php index 42044284a3..9f1f03129b 100755 --- a/config/app.php +++ b/config/app.php @@ -270,6 +270,18 @@ return [ 'lock_passwords' => env('APP_LOCKED', false), + /* + |-------------------------------------------------------------------------- + | Minimum PHP version + |-------------------------------------------------------------------------- + | + | Do not change this variable. + | + */ + + 'min_php' => '7.1.3', + + /* |-------------------------------------------------------------------------- | Autoloaded Service Providers @@ -321,7 +333,7 @@ return [ Laravel\Passport\PassportServiceProvider::class, Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, - Schuppo\PasswordStrength\PasswordStrengthServiceProvider::class, + //Schuppo\PasswordStrength\PasswordStrengthServiceProvider::class, Tightenco\Ziggy\ZiggyServiceProvider::class, // Laravel routes in vue Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, @@ -340,6 +352,8 @@ return [ * Custom service provider */ App\Providers\MacroServiceProvider::class, + App\Providers\LdapServiceProvider::class, + App\Providers\SamlServiceProvider::class, ], @@ -389,12 +403,12 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, - 'Input' => Illuminate\Support\Facades\Input::class, + //'Input' => Illuminate\Support\Facades\Input::class, 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, - 'Google2FA' => PragmaRX\Google2FA\Vendor\Laravel\Facade::class, - 'Debugbar' => Barryvdh\Debugbar\Facade::class, - 'Image' => Intervention\Image\ImageManagerStatic::class, + 'Google2FA' => PragmaRX\Google2FALaravel\Facade::class, + // 'Debugbar' => Barryvdh\Debugbar\Facade::class, //autodiscover should handle this + 'Image' => Intervention\Image\ImageServiceProvider::class, 'Carbon' => Carbon\Carbon::class, diff --git a/config/auth.php b/config/auth.php index 1206b682b2..d8a161f9f4 100644 --- a/config/auth.php +++ b/config/auth.php @@ -53,6 +53,7 @@ return [ 'api' => [ 'driver' => 'passport', 'provider' => 'users', + 'hash' => false, ], ], @@ -86,10 +87,6 @@ return [ | Resetting Passwords |-------------------------------------------------------------------------- | - | Here you may set the options for resetting passwords including the view - | that is your password reset e-mail. You may also set the name of the - | table that maintains all of the reset tokens for your application. - | | You may specify multiple password reset configurations if you have more | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. @@ -105,25 +102,22 @@ return [ 'provider' => 'users', 'email' => 'auth.emails.password', 'table' => 'password_resets', - 'expire' => 60, + 'expire' => env('LOGIN_LOCKOUT_DURATION', 60), + 'throttle' => env('LOGIN_MAX_ATTEMPTS', 60), ], ], /* - |-------------------------------------------------------------------------- - | Login throttling - |-------------------------------------------------------------------------- - | - | This handles the max failed login attempt throttling. - | You should not change the values here, but should change them in your - | application's .env file instead, as future changes to this file could - | overwrite your changes here. - | - */ + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the amount of seconds before a password confirmation + | times out and the user is prompted to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ - 'throttle' => [ - 'max_attempts' => env('LOGIN_MAX_ATTEMPTS', 10), - 'lockout_duration' => env('LOGIN_LOCKOUT_DURATION', 60), - ], + 'password_timeout' => 10800, ]; diff --git a/config/backup.php b/config/backup.php index ec1171a008..dd5714957f 100644 --- a/config/backup.php +++ b/config/backup.php @@ -1,9 +1,17 @@ [ - 'mysql', + env('DB_CONNECTION', 'mysql'), ], ], @@ -97,7 +105,7 @@ return [ * The disk names on which the backups will be stored. */ 'disks' => [ - 'local', + 'backup', ], ], @@ -158,7 +166,7 @@ return [ 'monitorBackups' => [ [ 'name' => config('app.name'), - 'disks' => ['local'], + 'disks' => [env('PRIVATE_FILESYSTEM_DISK', 'local')], 'newestBackupsShouldNotBeOlderThanDays' => 1, 'storageUsedMayNotBeHigherThanMegabytes' => 5000, ], @@ -205,7 +213,7 @@ return [ /* * The number of months for which one monthly backup must be kept. */ - 'keepMonthlyBackupsForMonths' => 4, + 'keepMonthlyBackupsForMonths' => 3, /* * The number of years for which one yearly backup must be kept. diff --git a/config/database.php b/config/database.php index 603c0c14d9..f32810326a 100755 --- a/config/database.php +++ b/config/database.php @@ -82,11 +82,14 @@ return [ 'unix_socket' => env('DB_SOCKET',''), 'dump' => [ 'dump_binary_path' => env('DB_DUMP_PATH', '/usr/local/bin'), // only the path, so without 'mysqldump' - 'use_single_transaction', + 'use_single_transaction' => false, 'timeout' => 60 * 5, // 5 minute timeout //'exclude_tables' => ['table1', 'table2'], //'add_extra_option' => '--optionname=optionvalue', ], + + 'dump_command_timeout' => 60 * 5, // 5 minute timeout + 'dump_using_single_transaction' => true, // perform dump using a single transaction 'options' => (env('DB_SSL')) ? ((env('DB_SSL_IS_PAAS')) ? [ PDO::MYSQL_ATTR_SSL_CA => env('DB_SSL_CA_PATH'), // /path/to/ca.pem ] : [ diff --git a/config/filesystems.php b/config/filesystems.php index 568fd1e4ab..b4bf6303e4 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -1,15 +1,6 @@ env('FILESYSTEM_DISK', 'local'), + 'default' => env('PRIVATE_FILESYSTEM_DISK', 'local'), /* |-------------------------------------------------------------------------- @@ -37,7 +26,7 @@ return [ | */ - 'cloud' => 's3', + 'cloud' => env('FILESYSTEM_CLOUD', 's3'), /* |-------------------------------------------------------------------------- @@ -48,47 +37,72 @@ return [ | may even configure multiple disks of the same driver. Defaults have | been setup for each driver as an example of the required options. | + | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace" + | */ 'disks' => [ 'local' => [ 'driver' => 'local', - 'root' => storage_path('app'), + 'root' => storage_path(), ], - 'ftp' => [ - 'driver' => 'ftp', - 'host' => 'ftp.example.com', - 'username' => 'your-username', - 'password' => 'your-password', - - // Optional FTP Settings... - // 'port' => 21, - // 'root' => '', - // 'passive' => true, - // 'ssl' => true, - // 'timeout' => 30, + // This applies the LOCAL public only, not S3/FTP/etc + 'local_public' => [ + 'driver' => 'local', + 'root' => public_path('uploads'), + 'url' => env('APP_URL').'/uploads', + 'visibility' => 'public', ], - 's3' => [ + 's3_public' => [ 'driver' => 's3', - 'key' => env('AWS_KEY', null), - 'secret' => env('AWS_SECRET', null), - 'region' => env('AWS_REGION', null), - 'bucket' => env('AWS_BUCKET', null), + 'key' => env('PUBLIC_AWS_ACCESS_KEY_ID'), + 'secret' => env('PUBLIC_AWS_SECRET_ACCESS_KEY'), + 'region' => env('PUBLIC_AWS_DEFAULT_REGION'), + 'bucket' => env('PUBLIC_AWS_BUCKET'), + 'url' => env('PUBLIC_AWS_URL'), + 'root' => env('PUBLIC_AWS_BUCKET_ROOT'), + 'visibility' => 'public' + ], + + 's3_private' => [ + // This bucket (if different than the 's3' bucket above) can be + // configured within AWS to *never* permit public documents + // For security reasons, its best to use separate buckets for + // public and private documents in S3 + 'driver' => 's3', + 'key' => env('PRIVATE_AWS_ACCESS_KEY_ID'), + 'secret' => env('PRIVATE_AWS_SECRET_ACCESS_KEY'), + 'region' => env('PRIVATE_AWS_DEFAULT_REGION'), + 'bucket' => env('PRIVATE_AWS_BUCKET'), + 'url' => env('PRIVATE_AWS_URL'), + 'root' => env('PRIVATE_AWS_BUCKET_ROOT'), + 'visibility' => 'private' ], 'rackspace' => [ 'driver' => 'rackspace', - 'username' => 'your-username', - 'key' => 'your-key', - 'container' => 'your-container', + 'username' => env('RACKSPACE_USERNAME'), + 'key' => env('RACKSPACE_KEY'), + 'container' => env('RACKSPACE_CONTAINER'), 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', - 'region' => 'IAD', - 'url_type' => 'publicURL', + 'region' => env('RACKSPACE_REGION'), + 'url_type' => env('RACKSPACE_URL_TYPE'), + ], + + 'backup' => [ + 'driver' => env('PRIVATE_FILESYSTEM_DISK', 'local'), + 'root' => storage_path('app'), ], ], ]; + +// copy the selected PUBLIC_FILESYSTEM_DISK's configuration to the 'public' key for easy use +// (by default, the PUBLIC_FILESYSTEM DISK is 'local_public', in the public/uploads directory) +$config['disks']['public'] = $config['disks'][env('PUBLIC_FILESYSTEM_DISK','local_public')]; + +return $config; diff --git a/config/hashing.php b/config/hashing.php new file mode 100644 index 0000000000..d3c8e2fb22 --- /dev/null +++ b/config/hashing.php @@ -0,0 +1,52 @@ + 'bcrypt', + + /* + |-------------------------------------------------------------------------- + | Bcrypt Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Bcrypt algorithm. This will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Argon Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Argon algorithm. These will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'argon' => [ + 'memory' => 1024, + 'threads' => 2, + 'time' => 2, + ], + +]; diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000000..86641787c0 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,81 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", + | "custom", "stack" + | + */ + + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['single'], + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('APP_LOG_LEVEL', 'error'), + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + 'days' => env('APP_LOG_MAX_FILES', 5), + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'Laravel Log', + 'emoji' => ':boom:', + 'level' => 'critical', + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'handler' => StreamHandler::class, + 'with' => [ + 'stream' => 'php://stderr', + ], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('APP_LOG_LEVEL', 'error'), + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('APP_LOG_LEVEL', 'error'), + ], + ], + +]; diff --git a/config/mail-auto-embed.php b/config/mail-auto-embed.php new file mode 100644 index 0000000000..bc1d038e0a --- /dev/null +++ b/config/mail-auto-embed.php @@ -0,0 +1,28 @@ + env('MAIL_AUTO_EMBED', true), + + /* + |-------------------------------------------------------------------------- + | Mail embed method + |-------------------------------------------------------------------------- + | + | Supported: "attachment", "base64" + | + */ + + 'method' => env('MAIL_AUTO_EMBED_METHOD', 'base64'), + +]; diff --git a/config/passport.php b/config/passport.php new file mode 100644 index 0000000000..1d9244514a --- /dev/null +++ b/config/passport.php @@ -0,0 +1,15 @@ + env('PASSPORT_PRIVATE_KEY'), + 'public_key' => env('PASSPORT_PUBLIC_KEY'), +]; \ No newline at end of file diff --git a/config/permissions.php b/config/permissions.php index 7ffa69e491..a17857161e 100644 --- a/config/permissions.php +++ b/config/permissions.php @@ -261,6 +261,41 @@ return array( ), + 'Kits' => array( + array( + 'permission' => 'kits.view', + 'label' => 'View ', + 'note' => 'These are predefined kits that can be used to quickly checkout assets, licenses, etc.', + 'display' => true, + ), + array( + 'permission' => 'kits.create', + 'label' => 'Create ', + 'note' => '', + 'display' => true, + ), + array( + 'permission' => 'kits.edit', + 'label' => 'Edit ', + 'note' => '', + 'display' => true, + ), + array( + 'permission' => 'kits.delete', + 'label' => 'Delete ', + 'note' => '', + 'display' => true, + ), + + array( + 'permission' => 'kits.checkout', + 'label' => 'Checkout ', + 'note' => '', + 'display' => true, + ), + ), + + 'Users' => array( array( 'permission' => 'users.view', @@ -587,6 +622,13 @@ return array( 'display' => true, ), + array( + 'permission' => 'self.checkout_assets', + 'label' => 'Self-Checkout', + 'note' => 'This user may check out assets that are marked for self-checkout.', + 'display' => true, + ), + ), diff --git a/config/session.php b/config/session.php index 1d36eb4901..d6710975a6 100644 --- a/config/session.php +++ b/config/session.php @@ -67,7 +67,7 @@ return [ | */ - 'files' => storage_path('framework/sessions'), + 'files' => (env('SESSION_PATH')!='' ? env('SESSION_PATH') : storage_path('framework/sessions')), /* |-------------------------------------------------------------------------- diff --git a/config/trustedproxy.php b/config/trustedproxy.php index fbfdcfbcc4..bde40fc7e8 100644 --- a/config/trustedproxy.php +++ b/config/trustedproxy.php @@ -21,7 +21,7 @@ return [ * within TrustedProxy to trust any proxy * that connects directly to your server, * a requirement when you cannot know the address - * of your proxy (e.g. if using Rackspace balancers). + * of your proxy (e.g. if using ELB or similar). * * The "**" character is syntactic sugar within * TrustedProxy to trust not just any proxy that @@ -33,42 +33,31 @@ return [ * how many proxies that client's request has * subsequently passed through. */ - 'proxies' => env('APP_TRUSTED_PROXIES') !== null ? - explode(',', env('APP_TRUSTED_PROXIES')) : '*', + 'proxies' => null, // [,], '*' + + /* + * To trust one or more specific proxies that connect + * directly to your server, use an array of IP addresses: + */ + # 'proxies' => ['192.168.1.1'], /* * Or, to trust all proxies that connect - * directly to your server, uncomment this: + * directly to your server, use a "*" */ - // 'proxies' => '*', + # 'proxies' => '*', /* - * Or, to trust ALL proxies, including those that - * are in a chain of forwarding, uncomment this: - */ - // 'proxies' => '**', - - /* - * Default Header Names + * Which headers to use to detect proxy related data (For, Host, Proto, Port) * - * Change these if the proxy does - * not send the default header names. + * Options include: * - * Note that headers such as X-Forwarded-For - * are transformed to HTTP_X_FORWARDED_FOR format. + * - Illuminate\Http\Request::HEADER_X_FORWARDED_ALL (use all x-forwarded-* headers to establish trust) + * - Illuminate\Http\Request::HEADER_FORWARDED (use the FORWARDED header to establish trust) * - * The following are Symfony defaults, found in - * \Symfony\Component\HttpFoundation\Request::$trustedHeaders - * - * We may also want to add something like: - * \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_SCHEME', + * @link https://symfony.com/doc/current/deployment/proxies.html */ - // These are defaults already set in the config: - 'headers' => [ - (defined('Illuminate\Http\Request::HEADER_FORWARDED') ? Illuminate\Http\Request::HEADER_FORWARDED : 'forwarded') => 'FORWARDED', - \Illuminate\Http\Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - \Illuminate\Http\Request::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - \Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ] + 'headers' => Illuminate\Http\Request::HEADER_X_FORWARDED_ALL, + + ]; diff --git a/config/version.php b/config/version.php index 9ca3050de2..ab48f18b94 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,11 @@ 'v4.9.5', - 'full_app_version' => 'v4.9.5 - build 4482-g5b68a321a', + + 'app_version' => 'v5.0.0-beta-4', + 'full_app_version' => 'v5.0.0-beta-4 - build 4482-g5b68a321a', 'build_version' => '4482', 'prerelease_version' => '', 'hash_version' => 'g5b68a321a', - 'full_hash' => 'v4.9.5-44-g5b68a321a', - 'branch' => 'master', + 'full_hash' => 'v5.0.0-beta-4-44-g5b68a321a', + 'branch' => 'develop', ); diff --git a/database/factories/AccessoryFactory.php b/database/factories/AccessoryFactory.php index 352f0b1540..9e69004862 100644 --- a/database/factories/AccessoryFactory.php +++ b/database/factories/AccessoryFactory.php @@ -21,6 +21,7 @@ $factory->state(App\Models\Accessory::class, 'apple-bt-keyboard', function ($fak return [ 'name' => 'Bluetooth Keyboard', + 'image' => 'bluetooth.jpg', 'category_id' => 8, 'manufacturer_id' => 1, 'qty' => 10, @@ -34,6 +35,7 @@ $factory->state(App\Models\Accessory::class, 'apple-usb-keyboard', function ($fa return [ 'name' => 'USB Keyboard', + 'image' => 'usb-keyboard.jpg', 'category_id' => 8, 'manufacturer_id' => 1, 'qty' => 15, @@ -47,6 +49,7 @@ $factory->state(App\Models\Accessory::class, 'apple-mouse', function ($faker) { return [ 'name' => 'Magic Mouse', + 'image' => 'magic-mouse.jpg', 'category_id' => 9, 'manufacturer_id' => 1, 'qty' => 13, @@ -60,6 +63,7 @@ $factory->state(App\Models\Accessory::class, 'microsoft-mouse', function ($faker return [ 'name' => 'Sculpt Comfort Mouse', + 'image' => 'comfort-mouse.jpg', 'category_id' => 9, 'manufacturer_id' => 2, 'qty' => 13, diff --git a/database/factories/AssetModelFactory.php b/database/factories/AssetModelFactory.php index d634588785..89cb21578c 100644 --- a/database/factories/AssetModelFactory.php +++ b/database/factories/AssetModelFactory.php @@ -33,6 +33,7 @@ $factory->state(App\Models\AssetModel::class, 'mbp-13-model', function ($faker) 'eol' => '36', 'depreciation_id' => 1, 'image' => 'mbp.jpg', + 'fieldset_id' => 2, ]; }); @@ -45,6 +46,7 @@ $factory->state(App\Models\AssetModel::class, 'mbp-air-model', function ($faker) 'eol' => '36', 'depreciation_id' => 1, 'image' => 'macbookair.jpg', + 'fieldset_id' => 2, ]; }); @@ -57,6 +59,7 @@ $factory->state(App\Models\AssetModel::class, 'surface-model', function ($faker) 'eol' => '36', 'depreciation_id' => 1, 'image' => 'surface.jpg', + 'fieldset_id' => 2, ]; }); @@ -69,6 +72,7 @@ $factory->state(App\Models\AssetModel::class, 'xps13-model', function ($faker) { 'eol' => '36', 'depreciation_id' => 1, 'image' => 'xps.jpg', + 'fieldset_id' => 2, ]; }); @@ -81,6 +85,7 @@ $factory->state(App\Models\AssetModel::class, 'zenbook-model', function ($faker) 'eol' => '36', 'depreciation_id' => 1, 'image' => 'zenbook.jpg', + 'fieldset_id' => 2, ]; }); @@ -93,6 +98,7 @@ $factory->state(App\Models\AssetModel::class, 'spectre-model', function ($faker) 'eol' => '36', 'depreciation_id' => 1, 'image' => 'spectre.jpg', + 'fieldset_id' => 2, ]; }); @@ -105,6 +111,7 @@ $factory->state(App\Models\AssetModel::class, 'yoga-model', function ($faker) { 'eol' => '36', 'depreciation_id' => 1, 'image' => 'yoga.png', + 'fieldset_id' => 2, ]; }); @@ -123,6 +130,7 @@ $factory->state(App\Models\AssetModel::class, 'macpro-model', function ($faker) 'eol' => '24', 'depreciation_id' => 1, 'image' => 'imacpro.jpg', + 'fieldset_id' => 2, ]; }); @@ -134,6 +142,7 @@ $factory->state(App\Models\AssetModel::class, 'lenovo-i5-model', function ($fake 'eol' => '24', 'depreciation_id' => 1, 'image' => 'lenovoi5.png', + 'fieldset_id' => 2, ]; }); @@ -146,6 +155,7 @@ $factory->state(App\Models\AssetModel::class, 'optiplex-model', function ($faker 'eol' => '24', 'depreciation_id' => 1, 'image' => 'optiplex.jpg', + 'fieldset_id' => 2, ]; }); @@ -224,6 +234,7 @@ $factory->state(App\Models\AssetModel::class, 'iphone6s-model', function ($faker 'eol' => '12', 'depreciation_id' => 3, 'image' => 'iphone6.jpg', + 'fieldset_id' => 1, ]; }); @@ -235,6 +246,7 @@ $factory->state(App\Models\AssetModel::class, 'iphone7-model', function ($faker) 'eol' => '12', 'depreciation_id' => 1, 'image' => 'iphone7.jpg', + 'fieldset_id' => 1, ]; }); diff --git a/database/factories/CustomFieldsFactory.php b/database/factories/CustomFieldsFactory.php index e6b35df0d1..7840014fd0 100644 --- a/database/factories/CustomFieldsFactory.php +++ b/database/factories/CustomFieldsFactory.php @@ -9,9 +9,40 @@ $factory->define(App\Models\CustomField::class, function (Faker\Generator $faker ]; }); -$factory->define(App\Models\CustomFieldset::class, function (Faker\Generator $faker) { +$factory->state(App\Models\CustomField::class, 'imei', function ($faker) { return [ - 'name' => $faker->catchPhrase, - 'user_id' => Auth::id() + 'name' => 'IMEI', + 'help_text' => 'The IMEI number for this device.', + 'format' => 'regex:/^[0-9]{15}$/', ]; }); + +$factory->state(App\Models\CustomField::class, 'phone', function ($faker) { + return [ + 'name' => 'Phone Number', + 'help_text' => 'Enter the phone number for this device.', + ]; +}); + +$factory->state(App\Models\CustomField::class, 'ram', function ($faker) { + return [ + 'name' => 'RAM', + 'help_text' => 'The amount of RAM this device has.', + ]; +}); + +$factory->state(App\Models\CustomField::class, 'cpu', function ($faker) { + return [ + 'name' => 'CPU', + 'help_text' => 'The speed of the processor on this device.', + ]; +}); + + +$factory->state(App\Models\CustomField::class, 'mac-address', function ($faker) { + return [ + 'name' => 'MAC Address', + 'format' => 'regex:/^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/', + ]; +}); + diff --git a/database/factories/CustomFieldsetFactory.php b/database/factories/CustomFieldsetFactory.php new file mode 100644 index 0000000000..bab8cbe58f --- /dev/null +++ b/database/factories/CustomFieldsetFactory.php @@ -0,0 +1,23 @@ +define(App\Models\CustomFieldset::class, function (Faker\Generator $faker) { + return [ + 'name' => $faker->catchPhrase, + ]; +}); + +$factory->state(App\Models\CustomFieldset::class, 'mobile', function ($faker) { + return [ + 'name' => 'Mobile Devices', + ]; +}); + +$factory->state(App\Models\CustomFieldset::class, 'computer', function ($faker) { + return [ + 'name' => 'Laptops and Desktops', + ]; +}); + + + diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 76dd0617b0..ad903e33ba 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -45,6 +45,11 @@ $factory->define(App\Models\Component::class, function (Faker\Generator $faker) ]; }); +$factory->define(App\Models\Group::class, function (Faker\Generator $faker) { + return [ + 'name' => $faker->name, + ]; +}); $factory->define(App\Models\Location::class, function (Faker\Generator $faker) { return [ diff --git a/database/migrations/2015_09_22_003413_migrate_mac_address.php b/database/migrations/2015_09_22_003413_migrate_mac_address.php index ff31042f9a..6345773ca1 100644 --- a/database/migrations/2015_09_22_003413_migrate_mac_address.php +++ b/database/migrations/2015_09_22_003413_migrate_mac_address.php @@ -21,7 +21,7 @@ class MigrateMacAddress extends Migration { } $macid=DB::table('custom_fields')->insertGetId([ 'name' => "MAC Address", - 'format' => \App\Models\CustomField::$PredefinedFormats['MAC'], + 'format' => \App\Models\CustomField::PREDEFINED_FORMATS['MAC'], 'element'=>'text']); if(!$macid) { throw new Exception("Can't save MAC Custom field: $macid"); diff --git a/database/migrations/2016_12_27_212631_make_asset_assigned_to_polymorphic.php b/database/migrations/2016_12_27_212631_make_asset_assigned_to_polymorphic.php index 3973abbcc3..772bd170a5 100644 --- a/database/migrations/2016_12_27_212631_make_asset_assigned_to_polymorphic.php +++ b/database/migrations/2016_12_27_212631_make_asset_assigned_to_polymorphic.php @@ -18,9 +18,9 @@ class MakeAssetAssignedToPolymorphic extends Migration Schema::table('assets', function (Blueprint $table) { $table->string('assigned_type')->nullable(); }); - - // Prior to this migration, asset's could only be assigned to users. - Asset::whereNotNull('assigned_to')->orWhere('assigned_to', '!=', null)->update(['assigned_type' => User::class]); + if(config('database.default') == 'mysql') { + Asset::whereNotNull('assigned_to')->orWhere('assigned_to', '!=', '')->update(['assigned_type' => User::class]); + } } /** diff --git a/database/migrations/2018_07_28_023826_create_checkout_acceptances_table.php b/database/migrations/2018_07_28_023826_create_checkout_acceptances_table.php new file mode 100644 index 0000000000..67bc3b800a --- /dev/null +++ b/database/migrations/2018_07_28_023826_create_checkout_acceptances_table.php @@ -0,0 +1,41 @@ +increments('id'); + + $table->morphs('checkoutable'); + $table->integer('assigned_to_id')->unsigned(); + + $table->string('signature_filename')->nullable(); + + $table->timestamp('accepted_at')->nullable(); + $table->timestamp('declined_at')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('checkout_acceptances'); + } +} diff --git a/database/migrations/2018_08_20_204842_add_depreciation_option_to_settings.php b/database/migrations/2018_08_20_204842_add_depreciation_option_to_settings.php new file mode 100644 index 0000000000..7678c45d56 --- /dev/null +++ b/database/migrations/2018_08_20_204842_add_depreciation_option_to_settings.php @@ -0,0 +1,32 @@ +char('depreciation_method', 10)->nullable()->default('default'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('depreciation_method'); + }); + } +} diff --git a/database/migrations/2018_09_10_082212_create_checkout_acceptances_for_unaccepted_assets.php b/database/migrations/2018_09_10_082212_create_checkout_acceptances_for_unaccepted_assets.php new file mode 100644 index 0000000000..ddf6949b69 --- /dev/null +++ b/database/migrations/2018_09_10_082212_create_checkout_acceptances_for_unaccepted_assets.php @@ -0,0 +1,43 @@ +where('assigned_type', 'App\Models\User')->where('accepted', 'pending')->get(); + + $acceptances = []; + + foreach($assets as $asset) { + $acceptances[] = [ + 'checkoutable_type' => 'App\Models\Asset', + 'checkoutable_id' => $asset->id, + 'assigned_to_id' => $asset->assigned_to, + ]; + } + + DB::table('checkout_acceptances')->insert($acceptances); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2018_10_18_191228_add_kits_licenses_table.php b/database/migrations/2018_10_18_191228_add_kits_licenses_table.php new file mode 100644 index 0000000000..44ca2c0a24 --- /dev/null +++ b/database/migrations/2018_10_18_191228_add_kits_licenses_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('license_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_licenses'); + } + +} diff --git a/database/migrations/2018_10_19_153910_add_kits_table.php b/database/migrations/2018_10_19_153910_add_kits_table.php new file mode 100644 index 0000000000..949c150146 --- /dev/null +++ b/database/migrations/2018_10_19_153910_add_kits_table.php @@ -0,0 +1,37 @@ +increments('id'); + $table->string('name')->nullable()->default(NULL); + $table->timestamps(); + $table->engine = 'InnoDB'; + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits'); + + } + +} diff --git a/database/migrations/2018_10_19_154013_add_kits_models_table.php b/database/migrations/2018_10_19_154013_add_kits_models_table.php new file mode 100644 index 0000000000..a0abeeef7b --- /dev/null +++ b/database/migrations/2018_10_19_154013_add_kits_models_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('model_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_models'); + } + +} diff --git a/database/migrations/2018_12_05_211936_add_favicon_to_settings.php b/database/migrations/2018_12_05_211936_add_favicon_to_settings.php new file mode 100644 index 0000000000..570eb53926 --- /dev/null +++ b/database/migrations/2018_12_05_211936_add_favicon_to_settings.php @@ -0,0 +1,32 @@ +char('favicon')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('favicon'); + }); + } +} diff --git a/database/migrations/2018_12_05_212119_add_email_logo_to_settings.php b/database/migrations/2018_12_05_212119_add_email_logo_to_settings.php new file mode 100644 index 0000000000..fd3a89170d --- /dev/null +++ b/database/migrations/2018_12_05_212119_add_email_logo_to_settings.php @@ -0,0 +1,32 @@ +char('email_logo')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('email_logo'); + }); + } +} diff --git a/database/migrations/2019_02_07_185953_add_kits_consumables_table.php b/database/migrations/2019_02_07_185953_add_kits_consumables_table.php new file mode 100644 index 0000000000..b6d14e4285 --- /dev/null +++ b/database/migrations/2019_02_07_185953_add_kits_consumables_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('consumable_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_consumables'); + } +} diff --git a/database/migrations/2019_02_07_190030_add_kits_accessories_table.php b/database/migrations/2019_02_07_190030_add_kits_accessories_table.php new file mode 100644 index 0000000000..f0e80249db --- /dev/null +++ b/database/migrations/2019_02_07_190030_add_kits_accessories_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('accessory_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_accessories'); + } +} diff --git a/database/migrations/2019_02_12_182750_add_actiondate_to_actionlog.php b/database/migrations/2019_02_12_182750_add_actiondate_to_actionlog.php new file mode 100644 index 0000000000..053b793b9a --- /dev/null +++ b/database/migrations/2019_02_12_182750_add_actiondate_to_actionlog.php @@ -0,0 +1,38 @@ +datetime('action_date')->nullable()->default(null); + }); + + $results = DB::table('action_logs')->select('created_at', 'id')->where('action_type', 'checkout')->orWhere('action_type', 'checkin from')->get(); + + foreach($results as $result){ + $update = DB::update('update '.DB::getTablePrefix().'action_logs set action_date=? where id=?', [$result->created_at, $result->id]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('action_logs', function (Blueprint $table) { + $table->dropColumn('action_date'); + }); + } +} diff --git a/database/migrations/2019_02_17_205048_add_label_logo_to_settings.php b/database/migrations/2019_02_17_205048_add_label_logo_to_settings.php new file mode 100644 index 0000000000..6811d3097b --- /dev/null +++ b/database/migrations/2019_02_17_205048_add_label_logo_to_settings.php @@ -0,0 +1,32 @@ +char('label_logo')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('label_logo'); + }); + } +} diff --git a/database/migrations/2019_07_23_140906_add_show_assigned_assets_to_settings.php b/database/migrations/2019_07_23_140906_add_show_assigned_assets_to_settings.php new file mode 100644 index 0000000000..d248bf911f --- /dev/null +++ b/database/migrations/2019_07_23_140906_add_show_assigned_assets_to_settings.php @@ -0,0 +1,32 @@ +boolean('show_assigned_assets')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('show_assigned_assets'); + }); + } +} diff --git a/database/migrations/2019_08_20_084049_add_custom_remote_user_header.php b/database/migrations/2019_08_20_084049_add_custom_remote_user_header.php new file mode 100644 index 0000000000..81b8b94f5a --- /dev/null +++ b/database/migrations/2019_08_20_084049_add_custom_remote_user_header.php @@ -0,0 +1,32 @@ +string('login_remote_user_header_name')->default(""); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('login_remote_user_header_name'); + }); + } +} diff --git a/database/migrations/2019_12_04_223111_passport_upgrade.php b/database/migrations/2019_12_04_223111_passport_upgrade.php new file mode 100644 index 0000000000..e38ff4654f --- /dev/null +++ b/database/migrations/2019_12_04_223111_passport_upgrade.php @@ -0,0 +1,32 @@ +string('secret', 100)->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('oauth_clients', function (Blueprint $table) { + $table->string('secret', 100)->change(); + }); + } +} diff --git a/database/migrations/2020_02_04_172100_add_ad_append_domain_settings.php b/database/migrations/2020_02_04_172100_add_ad_append_domain_settings.php new file mode 100644 index 0000000000..aced0bf111 --- /dev/null +++ b/database/migrations/2020_02_04_172100_add_ad_append_domain_settings.php @@ -0,0 +1,39 @@ +boolean('ad_append_domain')->nullable(false)->default('0'); + }); + + $s = Setting::first(); // we are deliberately *not* using the ::getSettings() method, as it caches things, and our Settings table is being migrated right now + if ($s && $s->is_ad && $s->ldap_enabled && $s->ad_domain) { //backwards-compatibility setting; < v5 always appended AD Domains + $s->ad_append_domain = 1; + $s->save(); + } +} + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('ad_append_domain'); + }); + } +} diff --git a/database/migrations/2020_04_29_222305_add_saml_fields_to_settings.php b/database/migrations/2020_04_29_222305_add_saml_fields_to_settings.php new file mode 100644 index 0000000000..90c656ce24 --- /dev/null +++ b/database/migrations/2020_04_29_222305_add_saml_fields_to_settings.php @@ -0,0 +1,48 @@ +boolean('saml_enabled')->default(0); + $table->text('saml_idp_metadata')->nullable()->default(NULL); + $table->string('saml_attr_mapping_username')->nullable()->default(NULL); + $table->boolean('saml_forcelogin')->default(0); + $table->boolean('saml_slo')->default(0); + $table->text('saml_sp_x509cert')->nullable()->default(NULL); + $table->text('saml_sp_privatekey')->nullable()->default(NULL); + $table->text('saml_custom_settings')->nullable()->default(NULL); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function(Blueprint $table) + { + $table->dropColumn('saml_enabled'); + $table->dropColumn('saml_idp_metadata'); + $table->dropColumn('saml_attr_mapping_username'); + $table->dropColumn('saml_forcelogin'); + $table->dropColumn('saml_slo'); + $table->dropColumn('saml_sp_x509cert'); + $table->dropColumn('saml_sp_privatekey'); + $table->dropColumn('saml_custom_settings'); + }); + } + +} diff --git a/database/seeds/AccessorySeeder.php b/database/seeds/AccessorySeeder.php index 9cb9e0aff6..a9041b782c 100644 --- a/database/seeds/AccessorySeeder.php +++ b/database/seeds/AccessorySeeder.php @@ -13,5 +13,31 @@ class AccessorySeeder extends Seeder factory(Accessory::class, 1)->states('apple-bt-keyboard')->create(); factory(Accessory::class, 1)->states('apple-mouse')->create(); factory(Accessory::class, 1)->states('microsoft-mouse')->create(); + + $src = public_path('/img/demo/accessories/'); + $dst = 'accessories'.'/'; + $del_files = Storage::files($dst); + + foreach($del_files as $del_file){ // iterate files + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } + } + + + $add_files = glob($src."/*.*"); + foreach($add_files as $add_file){ + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } + } } } diff --git a/database/seeds/AssetModelSeeder.php b/database/seeds/AssetModelSeeder.php index fdb1adef0a..c9f188ed10 100755 --- a/database/seeds/AssetModelSeeder.php +++ b/database/seeds/AssetModelSeeder.php @@ -2,6 +2,7 @@ use Illuminate\Database\Seeder; use App\Models\AssetModel; +use Illuminate\Support\Facades\Storage; class AssetModelSeeder extends Seeder { @@ -39,21 +40,30 @@ class AssetModelSeeder extends Seeder factory(AssetModel::class, 1)->states('ultrafine')->create(); // 17 factory(AssetModel::class, 1)->states('ultrasharp')->create(); // 18 - $src = public_path('/img/demo/models'); - $dst = public_path('/uploads/models'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/models/'); + $dst = 'models'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } diff --git a/database/seeds/AssetSeeder.php b/database/seeds/AssetSeeder.php index 79e47d6113..9bb9fd75db 100644 --- a/database/seeds/AssetSeeder.php +++ b/database/seeds/AssetSeeder.php @@ -1,7 +1,7 @@ states('ultrasharp')->create(); - $dst = public_path('/uploads/assets'); - - $del_files = glob($dst."/*.*"); - + $del_files = Storage::files('assets'); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + \Log::debug('Deleting: '.$del_files); + try { + Storage::disk('public')->delete('assets'.'/'.$del_files); + } catch (\Exception $e) { + \Log::debug($e); + } } DB::table('checkout_requests')->truncate(); diff --git a/database/seeds/CompanySeeder.php b/database/seeds/CompanySeeder.php index 3885b939f4..eeae5492b7 100644 --- a/database/seeds/CompanySeeder.php +++ b/database/seeds/CompanySeeder.php @@ -12,26 +12,37 @@ class CompanySeeder extends Seeder */ public function run() { - // + \Log::debug('Seed companies'); Company::truncate(); factory(Company::class, 4)->create(); - $src = public_path('/img/demo/companies'); - $dst = public_path('/uploads/companies'); - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/companies/'); + $dst = 'companies'.'/'; + $del_files = Storage::files('companies/'.$dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } + } } diff --git a/database/seeds/CustomFieldSeeder.php b/database/seeds/CustomFieldSeeder.php index 1186ec86f6..c743b3fc58 100644 --- a/database/seeds/CustomFieldSeeder.php +++ b/database/seeds/CustomFieldSeeder.php @@ -24,7 +24,41 @@ class CustomFieldSeeder extends Seeder CustomField::truncate(); CustomFieldset::truncate(); DB::table('custom_field_custom_fieldset')->truncate(); - factory(CustomField::class, 4)->create(); + + factory(CustomFieldset::class, 1)->states('mobile')->create(); + factory(CustomFieldset::class, 1)->states('computer')->create(); + factory(CustomField::class, 1)->states('imei')->create(); + factory(CustomField::class, 1)->states('phone')->create(); + factory(CustomField::class, 1)->states('ram')->create(); + factory(CustomField::class, 1)->states('cpu')->create(); + factory(CustomField::class, 1)->states('mac-address')->create(); + + DB::table('custom_field_custom_fieldset')->insert([ + [ + 'custom_field_id' => '1', + 'custom_fieldset_id' => '1' + ], + [ + 'custom_field_id' => '2', + 'custom_fieldset_id' => '1' + ], + [ + 'custom_field_id' => '3', + 'custom_fieldset_id' => '2' + ], + [ + 'custom_field_id' => '4', + 'custom_fieldset_id' => '2' + ], + [ + 'custom_field_id' => '5', + 'custom_fieldset_id' => '2' + ], + + ]); + + + } } diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 0a1c97560f..f90326c058 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -15,13 +15,19 @@ class DatabaseSeeder extends Seeder { Model::unguard(); + // Only create default settings if they do not exist in the db. + if(!Setting::first()) { + // factory(Setting::class)->create(); + $this->call(SettingsSeeder::class); + } + $this->call(CompanySeeder::class); $this->call(CategorySeeder::class); + $this->call(LocationSeeder::class); $this->call(UserSeeder::class); $this->call(DepreciationSeeder::class); $this->call(DepartmentSeeder::class); $this->call(ManufacturerSeeder::class); - $this->call(LocationSeeder::class); $this->call(SupplierSeeder::class); $this->call(AssetModelSeeder::class); $this->call(DepreciationSeeder::class); @@ -34,10 +40,7 @@ class DatabaseSeeder extends Seeder $this->call(ActionlogSeeder::class); $this->call(CustomFieldSeeder::class); - // Only create default settings if they do not exist in the db. - if(!Setting::first()) { - factory(Setting::class)->create(); - } + Artisan::call('snipeit:sync-asset-locations', ['--output' => 'all']); $output = Artisan::output(); \Log::info($output); @@ -45,6 +48,9 @@ class DatabaseSeeder extends Seeder Model::reguard(); DB::table('imports')->truncate(); + DB::table('asset_maintenances')->truncate(); + DB::table('requested_assets')->truncate(); + } } diff --git a/database/seeds/LocationSeeder.php b/database/seeds/LocationSeeder.php index 40d389792f..f7d857f34d 100644 --- a/database/seeds/LocationSeeder.php +++ b/database/seeds/LocationSeeder.php @@ -1,7 +1,7 @@ create(); - $src = public_path('/img/demo/locations'); - $dst = public_path('/uploads/locations'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/locations/'); + $dst = 'locations'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } } diff --git a/database/seeds/ManufacturerSeeder.php b/database/seeds/ManufacturerSeeder.php index f6d9a2451e..a65d12a2e4 100644 --- a/database/seeds/ManufacturerSeeder.php +++ b/database/seeds/ManufacturerSeeder.php @@ -1,6 +1,7 @@ states('avery')->create(); // 10 factory(Manufacturer::class, 1)->states('crucial')->create(); // 10 - $src = public_path('/img/demo/manufacturers'); - $dst = public_path('/uploads/manufacturers'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/manufacturers/'); + $dst = 'manufacturers'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } diff --git a/database/seeds/SettingsSeeder.php b/database/seeds/SettingsSeeder.php new file mode 100644 index 0000000000..f2b2e42ea5 --- /dev/null +++ b/database/seeds/SettingsSeeder.php @@ -0,0 +1,43 @@ +per_page = 20; + $settings->site_name = 'Snipe-IT Demo'; + $settings->auto_increment_assets = 1; + $settings->logo = 'logo.png'; + $settings->alert_email = 'service@snipe-it.io'; + $settings->header_color = null; + $settings->barcode_type = 'QRCODE'; + $settings->default_currency = 'USD'; + $settings->brand = 3; + $settings->ldap_enabled = 0; + $settings->full_multiple_companies_support = 0; + $settings->alt_barcode = 'C128'; + $settings->skin = ''; + $settings->email_domain = 'example.org'; + $settings->email_format = 'filastname'; + $settings->username_format = 'filastname'; + $settings->date_display_format = 'D M d, Y'; + $settings->time_display_format = 'g:iA'; + $settings->thumbnail_max_h = '30'; + $settings->locale = 'en'; + $settings->version_footer = 'on'; + $settings->support_footer = 'on'; + $settings->pwd_secure_min = '8'; + $settings->save(); + + if ($user = User::where('username', '=', 'admin')->first()) { + $user->locale = 'en'; + $user->save(); + } + } +} diff --git a/database/seeds/SupplierSeeder.php b/database/seeds/SupplierSeeder.php index 87ca416abd..8dbeac9964 100644 --- a/database/seeds/SupplierSeeder.php +++ b/database/seeds/SupplierSeeder.php @@ -9,22 +9,5 @@ class SupplierSeeder extends Seeder Supplier::truncate(); factory(Supplier::class, 5)->create(); - $src = public_path('/img/demo/suppliers'); - $dst = public_path('/uploads/suppliers'); - - $del_files = glob($dst."/*.*"); - - foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file - } - - - $add_files = glob($src."/*.*"); - foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); - } - } } diff --git a/docker/000-default-2.4.conf b/docker/000-default-2.4.conf new file mode 100644 index 0000000000..62a71adb8b --- /dev/null +++ b/docker/000-default-2.4.conf @@ -0,0 +1,19 @@ + + ServerAdmin webmaster@localhost + + DocumentRoot "/var/www/html/public" + DirectoryIndex index.php index.html + + Options All +MultiViews -ExecCGI -Indexes + + DAV Off + + AllowOverride All + Require all granted + + LogLevel warn + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/docker/entrypoint_alpine.sh b/docker/entrypoint_alpine.sh new file mode 100644 index 0000000000..6ea96189d4 --- /dev/null +++ b/docker/entrypoint_alpine.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +# fix key if needed +if [ -z "$APP_KEY" ] +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 + +#if [ ! -f /var/lib/snipeit/ssl/snipeit-ssl.crt -o ! -f /var/lib/snipeit/ssl/snipeit-ssl.key ] +#then + # rm /etc/apache2/conf.d/ssl.conf && rm /etc/apache2/conf.d/default-ssl.conf +#fi + +# 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 + +chown -R apache:root /var/lib/snipeit/data/* +chown -R apache:root /var/lib/snipeit/dumps +chown -R apache:root /var/lib/snipeit/keys + +# 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 + +php artisan migrate --force +php artisan config:clear +php artisan config:cache + +export APACHE_LOG_DIR=/var/log/apache2 +exec httpd -DNO_DETACH < /dev/null diff --git a/docker/startup.sh b/docker/startup.sh index 6921103de2..5fa32d1a93 100644 --- a/docker/startup.sh +++ b/docker/startup.sh @@ -56,3 +56,10 @@ then fi exec supervisord -c /supervisord.conf + +php artisan migrate --force +php artisan config:clear +php artisan config:cache + +. /etc/apache2/envvars +exec apache2 -DNO_DETACH < /dev/null diff --git a/gh-changelog.php b/gh-changelog.php deleted file mode 100644 index 8ca2fd26e9..0000000000 --- a/gh-changelog.php +++ /dev/null @@ -1,61 +0,0 @@ -view •'; - $gitlog .= ' %s \' --reverse | grep -i -E '.escapeshellarg($string).' '; - - if ($omit!=''){ - $gitlog .= ' | grep -i -E -v '.escapeshellarg($omit).''; - } - - $gitlog .= '>> '.escapeshellarg($file); - exec($gitlog); -} diff --git a/npm-shrinkwrap.json b/package-lock.json similarity index 65% rename from npm-shrinkwrap.json rename to package-lock.json index 83aa668e61..0ae45602dc 100644 --- a/npm-shrinkwrap.json +++ b/package-lock.json @@ -2,32 +2,45 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@fortawesome/fontawesome-free": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz", + "integrity": "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg==" + }, "@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha1-mgb08TfuhNffBGDB/bETX/psUP0=" + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" } }, "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "acorn-dynamic-import": { "version": "2.0.2", @@ -46,10 +59,25 @@ } } }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==" + }, "adjust-sourcemap-loader": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz", - "integrity": "sha1-4z/eleUNufKoAuNkfjEdL8UADGk=", + "integrity": "sha512-958oaHHVEXMvsY7v7cC5gEkNIcoaAVIhZ4mBReYVZJOTP9IgKmzLjIOhTtzpLMu+qriXvLsVjJ155EeInp45IQ==", "dev": true, "requires": { "assert": "^1.3.0", @@ -92,20 +120,71 @@ } } }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, + "adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "admin-lte": { + "version": "2.4.18", + "resolved": "https://registry.npmjs.org/admin-lte/-/admin-lte-2.4.18.tgz", + "integrity": "sha512-AfIdoUWdbQA0OmW7PnP8GJ3u6RMKNXefN3DRTBHCQXd7VeyJahUfZWtV62ppDxcdjpx0L08ypPV55ARmdGdOIw==", + "requires": { + "bootstrap": "^3.4", + "bootstrap-colorpicker": "^2.5.3", + "bootstrap-datepicker": "^1.8", + "bootstrap-daterangepicker": "^2.1.25", + "bootstrap-slider": "^9.10.0", + "chart.js": "^1", + "ckeditor": "^4.11.2", + "datatables.net": "^1.10.19", + "datatables.net-bs": "^1.10.19", + "fastclick": "^1.0.6", + "flot": "^0.8.3", + "font-awesome": "^4.7", + "fullcalendar": "^3.10", + "inputmask": "^3.3.7", + "ion-rangeslider": "^2.3", + "ionicons": "^3", + "jquery": "^3.4.1", + "jquery-knob": "^1.2.11", + "jquery-sparkline": "^2.4", + "jquery-ui": "^1.12.1", + "jvectormap": "^1.2.2", + "moment": "^2.24", + "morris.js": "^0.5", + "pace": "0.0.4", + "raphael": "^2.2.7", + "select2": "^4.0.3", + "slimscroll": "^0.9.1" + }, + "dependencies": { + "chart.js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-1.1.1.tgz", + "integrity": "sha1-qbFwVCIL1Fy9sXb9a8uHg++HGn0=" + } + } + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, "align-text": { @@ -142,15 +221,6 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -169,49 +239,37 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true - }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, - "archive-type": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz", - "integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=", - "dev": true, - "requires": { - "file-type": "^3.1.0" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true - } - } - }, "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -221,7 +279,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -236,7 +294,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-union": { @@ -245,12 +303,6 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -258,26 +310,26 @@ "dev": true }, "array-flatten": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", - "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", "dev": true }, "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" } }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, "requires": { "array-uniq": "^1.0.1" } @@ -285,8 +337,7 @@ "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, "array-unique": { "version": "0.3.2", @@ -301,15 +352,17 @@ "optional": true }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha1-ucK/WAXx5kqt7tbfOiv6+1pz9aA=", - "dev": true, + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -317,19 +370,33 @@ } }, "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "dev": true, + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "requires": { + "object-assign": "^4.1.1", "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } } }, "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", @@ -344,24 +411,18 @@ "dev": true }, "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.14.0" + "lodash": "^4.17.14" } }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "dev": true - }, - "async-each-series": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-1.1.0.tgz", - "integrity": "sha1-9C/YFV048hpbjqB8KOBj7RcAsTg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-foreach": { @@ -376,15 +437,15 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "autoprefixer": { "version": "7.2.6", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", - "integrity": "sha1-JWZy+G98c12oScTwfQCKuwVgZ9w=", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", "dev": true, "requires": { "browserslist": "^2.11.3", @@ -396,15 +457,14 @@ } }, "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, "axios": { "version": "0.19.2", @@ -413,17 +473,6 @@ "dev": true, "requires": { "follow-redirects": "1.5.10" - }, - "dependencies": { - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dev": true, - "requires": { - "debug": "=3.1.0" - } - } } }, "babel-code-frame": { @@ -464,6 +513,15 @@ "source-map": "^0.5.7" }, "dependencies": { + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -472,13 +530,25 @@ "requires": { "ms": "2.0.0" } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true } } }, "babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "dev": true, "requires": { "babel-messages": "^6.23.0", @@ -637,9 +707,9 @@ } }, "babel-loader": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz", - "integrity": "sha512-/hbyEvPzBJuGpk9o80R0ZyTej6heEOr59GoEUtn8qFKbnx4cJm9FWES6J/iv644sYgrtVw9JJQkjaLW/bqb5gw==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", "dev": true, "requires": { "find-cache-dir": "^1.0.0", @@ -818,9 +888,9 @@ } }, "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", - "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", "dev": true, "requires": { "babel-plugin-transform-strict-mode": "^6.24.1", @@ -984,9 +1054,9 @@ } }, "babel-preset-env": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", - "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", "dev": true, "requires": { "babel-plugin-check-es2015-constants": "^6.22.0", @@ -1016,9 +1086,21 @@ "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", "babel-plugin-transform-exponentiation-operator": "^6.22.0", "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^2.1.2", + "browserslist": "^3.2.6", "invariant": "^2.2.2", "semver": "^5.3.0" + }, + "dependencies": { + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + } } }, "babel-preset-es2015": { @@ -1141,7 +1223,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -1164,19 +1246,18 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -1200,7 +1281,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1209,7 +1290,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1218,7 +1299,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -1229,10 +1310,9 @@ } }, "base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", - "dev": true + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "batch": { "version": "0.6.1", @@ -1241,156 +1321,32 @@ "dev": true }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { "tweetnacl": "^0.14.3" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=" - }, - "bin-build": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-2.2.0.tgz", - "integrity": "sha1-EfjdYfcP/Por3KpbRvXo/t1CIcw=", - "dev": true, - "requires": { - "archive-type": "^3.0.1", - "decompress": "^3.0.0", - "download": "^4.1.2", - "exec-series": "^1.0.0", - "rimraf": "^2.2.6", - "tempfile": "^1.0.0", - "url-regex": "^3.0.0" - }, - "dependencies": { - "tempfile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz", - "integrity": "sha1-W8xOrsxKsscH2LwR2ZzMmiyyh/I=", - "dev": true, - "requires": { - "os-tmpdir": "^1.0.0", - "uuid": "^2.0.1" - } - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true - } - } - }, - "bin-check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-2.0.0.tgz", - "integrity": "sha1-hvjm9CU4k99g3DFpV/WvAqywWTA=", - "dev": true, - "requires": { - "executable": "^1.0.0" - } - }, - "bin-version": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-1.0.4.tgz", - "integrity": "sha1-nrSY7m/Xb3q5p8FgQ2+JV5Q1144=", - "dev": true, - "requires": { - "find-versions": "^1.0.0" - } - }, - "bin-version-check": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-2.1.0.tgz", - "integrity": "sha1-5OXfKQuQaffRETJAMe/BP90RpbA=", - "dev": true, - "requires": { - "bin-version": "^1.0.0", - "minimist": "^1.1.0", - "semver": "^4.0.3", - "semver-truncate": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - } - } - }, - "bin-wrapper": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-3.0.2.tgz", - "integrity": "sha1-Z9MwYmLksaXy+I7iNGT2plVneus=", - "dev": true, - "requires": { - "bin-check": "^2.0.0", - "bin-version-check": "^2.1.0", - "download": "^4.0.0", - "each-async": "^1.1.1", - "lazy-req": "^1.0.0", - "os-filter-obj": "^1.0.0" - } + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, + "optional": true, "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "file-uri-to-path": "1.0.0" } }, "block-stream": { @@ -1403,9 +1359,9 @@ } }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "blueimp-canvas-to-blob": { @@ -1415,9 +1371,9 @@ "optional": true }, "blueimp-file-upload": { - "version": "9.21.0", - "resolved": "https://registry.npmjs.org/blueimp-file-upload/-/blueimp-file-upload-9.21.0.tgz", - "integrity": "sha512-lDsM4m6PETB0CXyKZHiSQd/HhBCCTxMwGCUnnIDG46bVsUsL/McrodXwaNZ//poUopH46XQvBdY/SnJFKK3DEg==", + "version": "9.34.0", + "resolved": "https://registry.npmjs.org/blueimp-file-upload/-/blueimp-file-upload-9.34.0.tgz", + "integrity": "sha512-dXacFmyv6p0n+l5+u1ssYhSpCJdYabl7BZTw5WvB6ygY2ksTB3SdD6huafryEO5DH+XuspHDL6+IJ3m14Va+FQ==", "requires": { "blueimp-canvas-to-blob": "3.5.0", "blueimp-load-image": "2.12.2", @@ -1439,40 +1395,45 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", - "dev": true + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dev": true, "requires": { - "bytes": "3.0.0", + "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "dev": true } } @@ -1491,52 +1452,55 @@ "multicast-dns-service-types": "^1.1.0" } }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, "bootstrap": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", - "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" }, "bootstrap-colorpicker": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/bootstrap-colorpicker/-/bootstrap-colorpicker-2.5.2.tgz", - "integrity": "sha1-M7+yBDSF8S3LPfD2CtFxdizDwOQ=", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/bootstrap-colorpicker/-/bootstrap-colorpicker-2.5.3.tgz", + "integrity": "sha512-xdllX8LSMvKULs3b8JrgRXTvyvjkSMHHHVuHjjN5FNMqr6kRe5NPiMHFmeAFjlgDF73MspikudLuEwR28LbzLw==", "requires": { "jquery": ">=1.10" } }, "bootstrap-datepicker": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.8.0.tgz", - "integrity": "sha1-xjUTkx5vCfFq6fEbYvMtlQ3zlY4=", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.9.0.tgz", + "integrity": "sha512-9rYYbaVOheGYxjOr/+bJCmRPihfy+LkLSg4fIFMT9Od8WwWB/MB50w0JO1eBgKUMbb7PFHQD5uAfI3ArAxZRXA==", "requires": { "jquery": ">=1.7.1 <4.0.0" } }, + "bootstrap-daterangepicker": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-2.1.30.tgz", + "integrity": "sha1-+JPb//Wk19+qt1Rg6OppabuJaJo=", + "requires": { + "jquery": ">=1.10", + "moment": "^2.9.0" + } + }, "bootstrap-less": { "version": "3.3.8", "resolved": "https://registry.npmjs.org/bootstrap-less/-/bootstrap-less-3.3.8.tgz", "integrity": "sha1-cfKd1af//t/onxYFu63+CjONrlM=" }, + "bootstrap-slider": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/bootstrap-slider/-/bootstrap-slider-9.10.0.tgz", + "integrity": "sha1-EQPWvADPv6jPyaJZmrUYxVZD2j8=" + }, + "bootstrap-table": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.16.0.tgz", + "integrity": "sha512-bLbVetbyiXYmhU1LSsaiOHH4uvmlyBa/fNUo3y0owCfQSyQms/sfXOBvbcJWlDmjGtTY7kPW5z7KQvQJDPzN5w==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1545,7 +1509,7 @@ "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -1574,14 +1538,95 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "requires": { + "JSONStream": "^1.0.3", + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "browserify": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.1.tgz", + "integrity": "sha512-EQX0h59Pp+0GtSRb5rL6OTfrttlzv+uyaUVlK6GX3w11SQ0jKPKyjC/54RhPR2ib2KmfcELM06e8FxcI5XNU2A==", + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + } }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", - "dev": true, + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -1594,8 +1639,7 @@ "browserify-cipher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", - "dev": true, + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -1603,21 +1647,20 @@ } }, "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -1627,7 +1670,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, "requires": { "bn.js": "^4.1.1", "browserify-rsa": "^4.0.0", @@ -1641,8 +1683,7 @@ "browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", - "dev": true, + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { "pako": "~1.0.5" } @@ -1650,7 +1691,7 @@ "browserslist": { "version": "2.11.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", - "integrity": "sha1-/jYWeu0bvN5IJ+v+cTR6LMcLmbI=", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", "dev": true, "requires": { "caniuse-lite": "^1.0.30000792", @@ -1658,99 +1699,34 @@ } }, "buffer": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", - "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", - "dev": true, + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { - "base64-js": "0.0.8", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "buffer-alloc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", - "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", - "dev": true, - "requires": { - "buffer-alloc-unsafe": "^0.1.0", - "buffer-fill": "^0.1.0" - } - }, - "buffer-alloc-unsafe": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz", - "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo=", - "dev": true - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-fill": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.1.tgz", - "integrity": "sha512-YgBMBzdRLEfgxJIGu2wrvI2E03tMCFU1p7d1KhB4BOoMN0VxmTFjSyN5JtKt9z8Z9JajMHruI6SE25W96wNv7Q==", - "dev": true - }, "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "buffer-indexof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", "dev": true }, - "buffer-to-vinyl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", - "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=", - "dev": true, - "requires": { - "file-type": "^3.1.0", - "readable-stream": "^2.0.2", - "uuid": "^2.0.1", - "vinyl": "^1.0.0" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true - } - } - }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "bytes": { "version": "3.0.0", @@ -1761,7 +1737,7 @@ "cacache": { "version": "10.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha1-ZFI2eZnv+dQYiu/ZoU6dfGomNGA=", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { "bluebird": "^3.5.1", @@ -1782,7 +1758,7 @@ "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true } } @@ -1790,7 +1766,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -1816,8 +1792,44 @@ "lowercase-keys": "1.0.0", "normalize-url": "2.0.1", "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + } } }, + "cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, "camel-case": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", @@ -1865,25 +1877,25 @@ "caniuse-db": "^1.0.30000639", "electron-to-chromium": "^1.2.7" } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true } } }, "caniuse-db": { - "version": "1.0.30000832", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000832.tgz", - "integrity": "sha1-r+NMn3xiE5/RxgfbKrcwi7tqUVg=", + "version": "1.0.30001045", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001045.tgz", + "integrity": "sha512-bwCb2ssU32vcxjG1P2VBOi1YV9W7G3RCG9m2++cX6Kql1oR+5w7vUBFL2SO47svJRUw+ai/d7yNT5VqoA2g3Sw==", "dev": true }, "caniuse-lite": { - "version": "1.0.30000832", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000832.tgz", - "integrity": "sha512-WMC2GiGTPxGywFL70h+CnP7GAYo6LM6JSI1sF13vAZfXCzOeunHzl20DpfbDGMdvtT2wpqvabY96MHEp/la+BQ==", - "dev": true - }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "version": "1.0.30001045", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001045.tgz", + "integrity": "sha512-Y8o2Iz1KPcD6FjySbk1sPpvJqchgxk/iow0DABpGyzA1UeQAuxh63Xh0Enj5/BrsYbXtCN32JmR4ZxQTCQ6E6A==", "dev": true }, "caseless": { @@ -1891,32 +1903,6 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "caw": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/caw/-/caw-1.2.0.tgz", - "integrity": "sha1-/7Im/n78VHKI3GLuPpcHPCEtEDQ=", - "dev": true, - "requires": { - "get-proxy": "^1.0.1", - "is-obj": "^1.0.0", - "object-assign": "^3.0.0", - "tunnel-agent": "^0.4.0" - }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true - } - } - }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -1927,6 +1913,22 @@ "lazy-cache": "^1.0.3" } }, + "cf-blob.js": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/cf-blob.js/-/cf-blob.js-0.0.1.tgz", + "integrity": "sha1-9at+EueYyvCMz4KMaaug8GPYP5k=" + }, + "cfb": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.1.4.tgz", + "integrity": "sha512-rwFkl3aFO3f+ljR27YINwC0x8vPjyiEVbYbrTCKzspEf7Q++3THdfHVgJYNUbxNcupJECrLX+L40Mjm9hm/Bgw==", + "requires": { + "adler-32": "~1.2.0", + "commander": "^2.16.0", + "crc-32": "~1.2.0", + "printj": "~1.1.2" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -1946,46 +1948,81 @@ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", "dev": true }, + "charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=" + }, + "chart.js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz", + "integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==", + "requires": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "requires": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "requires": { + "color-name": "^1.0.0" + } + }, "chokidar": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", - "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.1.2", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", - "inherits": "^2.0.1", + "inherits": "^2.0.3", "is-binary-path": "^1.0.0", "is-glob": "^4.0.0", - "normalize-path": "^2.1.1", + "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.0" + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", - "dev": true, + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, + "ckeditor": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/ckeditor/-/ckeditor-4.12.1.tgz", + "integrity": "sha512-pH2Su4oi0D4iN/3U8nUcwI7/lXHoOJi0aiN8e2zxnm4Ow5kq8eZP2ZGmpYyuqRyKZ2tHaU8+OyYi7laXcjiq9Q==" + }, "clap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha1-TzZ0WzIAhJJVf0ZBLWbVDLmbzlE=", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", "dev": true, "requires": { "chalk": "^1.1.3" @@ -1994,7 +2031,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -2014,13 +2051,26 @@ } } }, + "classie": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/classie/-/classie-1.0.0.tgz", + "integrity": "sha1-/JsptH5k43SiBi+2JNBaYc1wOrI=" + }, "clean-css": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz", - "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "dev": true, "requires": { - "source-map": "0.5.x" + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "cliui": { @@ -2057,31 +2107,20 @@ } }, "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "clone-deep": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha1-ANs6Hhc2VnMNEYjD1qztbX6pdxM=", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", "dev": true, "requires": { "for-own": "^1.0.0", "is-plain-object": "^2.0.4", "kind-of": "^6.0.0", "shallow-clone": "^1.0.0" - }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - } } }, "clone-response": { @@ -2092,16 +2131,11 @@ "mimic-response": "^1.0.0" } }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, "coa": { "version": "1.0.4", @@ -2118,6 +2152,22 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=", + "requires": { + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" + }, + "dependencies": { + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" + } + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -2148,19 +2198,24 @@ } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" + }, + "dependencies": { + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-string": { "version": "0.3.0", @@ -2171,12 +2226,6 @@ "color-name": "^1.0.0" } }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", - "dev": true - }, "colormin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", @@ -2194,19 +2243,29 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" }, "commondir": { "version": "1.0.1", @@ -2215,32 +2274,32 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "compressible": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz", - "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "requires": { - "mime-db": ">= 1.33.0 < 2" + "mime-db": ">= 1.43.0 < 2" } }, "compression": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.2.tgz", - "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, "requires": { - "accepts": "~1.3.4", + "accepts": "~1.3.5", "bytes": "3.0.0", - "compressible": "~2.0.13", + "compressible": "~2.0.16", "debug": "2.6.9", - "on-headers": "~1.0.1", - "safe-buffer": "5.1.1", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", "vary": "~1.1.2" }, "dependencies": { @@ -2252,20 +2311,24 @@ "requires": { "ms": "2.0.0" } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true } } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "dev": true, + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -2282,30 +2345,16 @@ "globs": "^0.1.2" } }, - "config-chain": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", - "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "connect-history-api-fallback": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", - "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" }, "console-control-strings": { "version": "1.1.0", @@ -2313,12 +2362,6 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, - "console-stream": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz", - "integrity": "sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ=", - "dev": true - }, "consolidate": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", @@ -2331,31 +2374,40 @@ "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" }, "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", "dev": true }, "cookie-signature": { @@ -2367,7 +2419,7 @@ "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "dev": true, "requires": { "aproba": "^1.1.1", @@ -2385,9 +2437,9 @@ "dev": true }, "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true }, "core-util-is": { @@ -2396,52 +2448,67 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "requires": { + "import-fresh": "^2.0.0", "is-directory": "^0.3.1", - "js-yaml": "^3.4.3", - "minimist": "^1.2.0", - "object-assign": "^4.1.0", - "os-homedir": "^1.0.1", - "parse-json": "^2.2.0", - "require-from-string": "^1.1.0" + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" }, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } } } }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, "create-ecdh": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.1.tgz", - "integrity": "sha512-iZvCCg8XqHQZ1ioNBTzXS/cQSkqkqcPs8xSX4upNB+DAk9Ht3uzQf2J32uAHNCne8LDmKr29AgZrEs4oIrwLuQ==", - "dev": true, + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", - "dev": true, + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -2453,8 +2520,7 @@ "create-hmac": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", - "dev": true, + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -2465,22 +2531,23 @@ } }, "cross-env": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.1.3.tgz", - "integrity": "sha512-UOokgwvDzCT0mqRSLEkJzUhYXB1vK3E5UgDrD41QiXsm9UetcW2rCGHYz/O3p873lMJ1VZbFCF9Izkwh7nYR5A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz", + "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==", "dev": true, "requires": { - "cross-spawn": "^5.1.0", - "is-windows": "^1.0.0" + "cross-spawn": "^6.0.5" } }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "lru-cache": "^4.0.1", + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } @@ -2491,20 +2558,10 @@ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", "dev": true }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", - "dev": true, + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -2520,48 +2577,21 @@ } }, "css": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.1.tgz", - "integrity": "sha1-c6TIHehdtmTU7mdPfUcIXjstVdw=", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "requires": { - "inherits": "^2.0.1", - "source-map": "^0.1.38", - "source-map-resolve": "^0.3.0", + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", "urix": "^0.1.0" }, "dependencies": { - "atob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/atob/-/atob-1.1.3.tgz", - "integrity": "sha1-lfE2KbEsOlGl0hWr3OKqnzL4B3M=", - "dev": true - }, "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "source-map-resolve": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.3.1.tgz", - "integrity": "sha1-YQ9hIqRFuN1RU1oqcbeD38Ekh2E=", - "dev": true, - "requires": { - "atob": "~1.1.0", - "resolve-url": "~0.2.1", - "source-map-url": "~0.3.0", - "urix": "~0.1.0" - } - }, - "source-map-url": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz", - "integrity": "sha1-fsrxO1e80J2opAxdJp2zN5nUqvk=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -2575,7 +2605,7 @@ "css-loader": { "version": "0.28.11", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", - "integrity": "sha1-w/mGSnAL4nEbtaJGKyOJsaOS2rc=", + "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==", "dev": true, "requires": { "babel-code-frame": "^6.26.0", @@ -2603,7 +2633,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -2623,74 +2653,52 @@ } } }, - "css-select": { - "version": "1.3.0-rc0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.3.0-rc0.tgz", - "integrity": "sha1-b5MZaqrnN2ZuoQNqjLFKj8t6kjE=", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "^1.0.1" - } - }, - "css-select-base-adapter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz", - "integrity": "sha1-AQKz0UYw34bD65+p9UVicBBs+ZA=", - "dev": true - }, "css-selector-tokenizer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", - "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz", + "integrity": "sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw==", "dev": true, "requires": { - "cssesc": "^0.1.0", - "fastparse": "^1.1.1", - "regexpu-core": "^1.0.0" + "cssesc": "^3.0.0", + "fastparse": "^1.1.2", + "regexpu-core": "^4.6.0" }, "dependencies": { "regexpu-core": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", - "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", "dev": true, "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" } } } }, - "css-tree": { - "version": "1.0.0-alpha25", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha25.tgz", - "integrity": "sha1-G7+r+/bu708B2RCP8u3Qvi/jVZc=", - "dev": true, - "requires": { - "mdn-data": "^1.0.0", - "source-map": "^0.5.3" - } - }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", - "dev": true - }, - "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", - "dev": true - }, "cssesc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", - "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, "cssnano": { @@ -2766,7 +2774,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -2806,46 +2814,50 @@ } }, "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { - "es5-ext": "^0.10.9" + "es5-ext": "^0.10.50", + "type": "^1.0.1" } }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true + "datatables.net": { + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.20.tgz", + "integrity": "sha512-4E4S7tTU607N3h0fZPkGmAtr9mwy462u+VJ6gxYZ8MxcRIjZqHy3Dv1GNry7i3zQCktTdWbULVKBbkAJkuHEnQ==", + "requires": { + "jquery": ">=1.7" + } }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true + "datatables.net-bs": { + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.20.tgz", + "integrity": "sha512-NsMoOOYZ6NlteOpzhltw21lXsNdhjIMbIOxnqmcrb62ntl8eL9pYzk2AeiDXBlIKY4e550ZrExCq3CYKQ9myEg==", + "requires": { + "datatables.net": "1.10.20", + "jquery": ">=1.7" + } }, "de-indent": { "version": "1.0.2", @@ -2856,7 +2868,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -2873,23 +2885,6 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, - "decompress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz", - "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=", - "dev": true, - "requires": { - "buffer-to-vinyl": "^1.0.0", - "concat-stream": "^1.4.6", - "decompress-tar": "^3.0.0", - "decompress-tarbz2": "^3.0.0", - "decompress-targz": "^3.0.0", - "decompress-unzip": "^3.0.0", - "stream-combiner2": "^1.1.1", - "vinyl-assign": "^1.0.1", - "vinyl-fs": "^2.2.0" - } - }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -2898,174 +2893,33 @@ "mimic-response": "^1.0.0" } }, - "decompress-tar": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", - "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=", - "dev": true, - "requires": { - "is-tar": "^1.0.0", - "object-assign": "^2.0.0", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - } - } - }, - "decompress-tarbz2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz", - "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=", - "dev": true, - "requires": { - "is-bzip2": "^1.0.0", - "object-assign": "^2.0.0", - "seek-bzip": "^1.0.3", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - } - } - }, - "decompress-targz": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz", - "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=", - "dev": true, - "requires": { - "is-gzip": "^1.0.0", - "object-assign": "^2.0.0", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - } - } - }, - "decompress-unzip": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz", - "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=", - "dev": true, - "requires": { - "is-zip": "^1.0.0", - "read-all-stream": "^3.0.0", - "stat-mode": "^0.2.0", - "strip-dirs": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^1.0.0", - "yauzl": "^2.2.1" - }, - "dependencies": { - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } - } - }, "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true - }, - "deep-extend": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } }, "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "object-keys": "^1.0.12" } }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -3075,7 +2929,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3084,7 +2938,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3093,7 +2947,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3106,8 +2960,7 @@ "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" }, "del": { "version": "3.0.0", @@ -3121,6 +2974,14 @@ "p-map": "^1.1.1", "pify": "^3.0.0", "rimraf": "^2.2.8" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "delayed-stream": { @@ -3140,11 +3001,21 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -3166,16 +3037,25 @@ } }, "detect-node": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", - "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", "dev": true }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", - "dev": true, + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -3191,7 +3071,7 @@ "dns-packet": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha1-EqpCaYEHW+UAuRDu3NC0fdfe2lo=", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", "dev": true, "requires": { "ip": "^1.1.0", @@ -3207,44 +3087,19 @@ "buffer-indexof": "^1.0.0" } }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } - } - }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", - "dev": true + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", - "dev": true - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, + "domhelper": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/domhelper/-/domhelper-0.9.1.tgz", + "integrity": "sha1-JlVOW6wsnpWF3KUAl431Bn1kvQA=", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "browserify": ">=3.46.0", + "classie": ">=0.0.1", + "util-extend": "^1.0.1" } }, "dotenv": { @@ -3259,80 +3114,10 @@ "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=", "dev": true }, - "download": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz", - "integrity": "sha1-qlX9rTktldS2jowr4D4MKqIbqaw=", - "dev": true, - "requires": { - "caw": "^1.0.1", - "concat-stream": "^1.4.7", - "each-async": "^1.0.0", - "filenamify": "^1.0.1", - "got": "^5.0.0", - "gulp-decompress": "^1.2.0", - "gulp-rename": "^1.2.0", - "is-url": "^1.2.0", - "object-assign": "^4.0.1", - "read-all-stream": "^3.0.0", - "readable-stream": "^2.0.2", - "stream-combiner2": "^1.1.1", - "vinyl": "^1.0.0", - "vinyl-fs": "^2.2.0", - "ware": "^1.2.0" - }, - "dependencies": { - "got": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz", - "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=", - "dev": true, - "requires": { - "create-error-class": "^3.0.1", - "duplexer2": "^0.1.4", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "node-status-codes": "^1.0.0", - "object-assign": "^4.0.1", - "parse-json": "^2.1.0", - "pinkie-promise": "^2.0.0", - "read-all-stream": "^3.0.0", - "readable-stream": "^2.0.5", - "timed-out": "^3.0.0", - "unzip-response": "^1.0.2", - "url-parse-lax": "^1.0.0" - } - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "timed-out": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz", - "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=", - "dev": true - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - } - } - }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, "requires": { "readable-stream": "^2.0.2" } @@ -3343,9 +3128,9 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, "duplexify": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz", - "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -3354,23 +3139,13 @@ "stream-shift": "^1.0.0" } }, - "each-async": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", - "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", - "dev": true, - "requires": { - "onetime": "^1.0.0", - "set-immediate-shim": "^1.0.0" - } - }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ee-first": { @@ -3382,19 +3157,18 @@ "ekko-lightbox": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ekko-lightbox/-/ekko-lightbox-5.3.0.tgz", - "integrity": "sha1-+/zZ35Oo0c2/h3CtyMBaqsTST1Y=" + "integrity": "sha512-mbacwySuVD3Ad6F2hTkjSTvJt59bcVv2l/TmBerp4xZnLak8tPtA4AScUn4DL42c1ksTiAO6sGhJZ52P/1Qgew==" }, "electron-to-chromium": { - "version": "1.3.44", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.44.tgz", - "integrity": "sha1-72sVCmDVIwgjiMra2ICF7NL9RoQ=", + "version": "1.3.414", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.414.tgz", + "integrity": "sha512-UfxhIvED++qLwWrAq9uYVcqF8FdeV9sU2S7qhiHYFODxzXRrd1GZRl/PjITHsTEejgibcWDraD8TQqoHb1aCBQ==", "dev": true }, "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "dev": true, + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -3406,9 +3180,9 @@ } }, "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, "encodeurl": { "version": "1.0.2", @@ -3417,9 +3191,9 @@ "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -3437,71 +3211,71 @@ "tapable": "^0.2.7" } }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "requires": { "prr": "~1.0.1" } }, "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "error-stack-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.1.tgz", - "integrity": "sha1-oyArj7AxFKqbQKDjZp5IsrZaAQo=", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", "dev": true, "requires": { - "stackframe": "^1.0.3" + "stackframe": "^1.1.1" } }, "es-abstract": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", - "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" } }, "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { - "is-callable": "^1.1.1", + "is-callable": "^1.1.4", "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" + "is-symbol": "^1.0.2" } }, "es5-ext": { - "version": "0.10.42", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.42.tgz", - "integrity": "sha1-jAfdM68E1dzRMQtc7xO+pjqJuo0=", + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", "dev": true, "requires": { "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "1" + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" } }, "es6-iterator": { @@ -3529,6 +3303,11 @@ "event-emitter": "~0.3.5" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -3540,16 +3319,28 @@ "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } } }, "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "d": "^1.0.1", + "ext": "^1.1.2" } }, "es6-templates": { @@ -3563,14 +3354,14 @@ } }, "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, "requires": { "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.1" } }, @@ -3607,22 +3398,22 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "etag": { @@ -3631,6 +3422,11 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "eve-raphael": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eve-raphael/-/eve-raphael-0.5.0.tgz", + "integrity": "sha1-F8dUt5K+7z+maE15z1pHxjxM2jA=" + }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -3642,16 +3438,15 @@ } }, "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "dev": true }, "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==" }, "eventsource": { "version": "0.1.6", @@ -3665,36 +3460,12 @@ "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", - "dev": true, + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, - "exec-buffer": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", - "integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=", - "dev": true, - "requires": { - "execa": "^0.7.0", - "p-finally": "^1.0.0", - "pify": "^3.0.0", - "rimraf": "^2.5.4", - "tempfile": "^2.0.0" - } - }, - "exec-series": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/exec-series/-/exec-series-1.0.3.tgz", - "integrity": "sha1-bSV6m+rEgqhyx3g7yGFYOfx3FDo=", - "dev": true, - "requires": { - "async-each-series": "^1.1.0", - "object-assign": "^4.1.0" - } - }, "execa": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", @@ -3708,16 +3479,25 @@ "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } } }, - "executable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/executable/-/executable-1.1.0.tgz", - "integrity": "sha1-h3mA6REvM5EGbaNyZd562ENKtNk=", - "dev": true, - "requires": { - "meow": "^3.1.0" - } + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" }, "expand-brackets": { "version": "2.1.4", @@ -3737,7 +3517,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -3763,91 +3543,40 @@ } } }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "dev": true, "requires": { - "accepts": "~1.3.5", + "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", "content-type": "~1.0.4", - "cookie": "0.3.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.1.1", + "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, @@ -3861,43 +3590,47 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true } } }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha1-C5jmTtgvWs8PKTG6v2khLvUt3Tc=", + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", "dev": true, "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha1-cHgZgdGD7hXROZPIgiBFxQbI8KY=", - "dev": true, - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "dev": true + } } }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -3912,7 +3645,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -3923,7 +3656,7 @@ "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -3957,7 +3690,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3966,7 +3699,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3975,7 +3708,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3988,7 +3721,7 @@ "extract-text-webpack-plugin": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", - "integrity": "sha1-XwQ+qgL5dQqSWLeMCm4NwUCPsvc=", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", "dev": true, "requires": { "async": "^2.4.1", @@ -4002,31 +3735,30 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, - "fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" - } - }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fastclick": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fastclick/-/fastclick-1.0.6.tgz", + "integrity": "sha1-FhYlsnsaWAZAWTa9qaLBkm0Gvmo=" }, "fastparse": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", - "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", "dev": true }, "faye-websocket": { @@ -4038,62 +3770,31 @@ "websocket-driver": ">=0.5.1" } }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, "file-loader": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.11.2.tgz", - "integrity": "sha1-T/HfKK84cZpgmAk7iMgscdF5SjQ=", + "integrity": "sha512-N+uhF3mswIFeziHQjGScJ/yHXYt3DiLBeC+9vWW+WjUBiClMSOlV1YrXQi+7KM2aA3Rn4Bybgv+uXFQbfkzpvg==", "dev": true, "requires": { "loader-utils": "^1.0.2" } }, + "file-saver": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz", + "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==" + }, "file-type": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", - "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", - "dev": true + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=" }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "filename-reserved-regex": { + "file-uri-to-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz", - "integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=", - "dev": true - }, - "filenamify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz", - "integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true, - "requires": { - "filename-reserved-regex": "^1.0.0", - "strip-outer": "^1.0.0", - "trim-repeated": "^1.0.0" - } + "optional": true }, "fill-range": { "version": "4.0.0", @@ -4119,24 +3820,24 @@ } }, "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", "unpipe": "~1.0.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -4164,47 +3865,34 @@ "locate-path": "^2.0.0" } }, - "find-versions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-1.2.1.tgz", - "integrity": "sha1-y96fEuOFdaCvG+G5osXV/Y8Ya2I=", - "dev": true, - "requires": { - "array-uniq": "^1.0.0", - "get-stdin": "^4.0.1", - "meow": "^3.5.0", - "semver-regex": "^1.0.0" - } - }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true - }, "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", "dev": true }, + "flot": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/flot/-/flot-0.8.3.tgz", + "integrity": "sha512-xg2otcTJDvS+ERK+my4wxG/ASq90QURXtoM4LhacCq0jQW2jbyjdttbRNqU2cPykrpMvJ6b2uSp6SAgYAzj9tQ==" + }, "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha1-xdWG7zivYJdlC0m8QbVfq7GfNb0=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" } }, "follow-redirects": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", - "integrity": "sha1-2BIPRRgZD1Wqxlu2/HuF/NZm1qo=", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "dev": true, "requires": { - "debug": "^3.1.0" + "debug": "=3.1.0" } }, "font-awesome": { @@ -4219,33 +3907,26 @@ "dev": true }, "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { "for-in": "^1.0.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -4255,6 +3936,11 @@ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", "dev": true }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -4273,7 +3959,7 @@ "friendly-errors-webpack-plugin": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz", - "integrity": "sha1-78hsu4FiJFZYYaG+ep2E0Kr+oTY=", + "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -4290,12 +3976,6 @@ "readable-stream": "^2.0.0" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true - }, "fs-extra": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", @@ -4322,18 +4002,18 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", - "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", + "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.9.0" + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -4345,8 +4025,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -4355,7 +4034,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -4367,21 +4046,19 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.4", "bundled": true, "dev": true, "optional": true @@ -4389,20 +4066,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -4411,16 +4085,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "3.2.6", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.4.2", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -4438,12 +4112,12 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -4469,7 +4143,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.6", "bundled": true, "dev": true, "optional": true, @@ -4489,16 +4163,16 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true, @@ -4517,10 +4191,9 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -4532,7 +4205,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4547,82 +4219,78 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "0.0.8", + "version": "1.2.5", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.9.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.3.3", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { - "version": "0.5.1", + "version": "0.5.3", "bundled": true, "dev": true, - "optional": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "ms": { - "version": "2.0.0", + "version": "2.1.2", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.3", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.9.1", + "version": "0.14.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { - "version": "4.0.1", + "version": "4.0.3", "bundled": true, "dev": true, "optional": true, @@ -4632,19 +4300,28 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.1.1", "bundled": true, "dev": true, - "optional": true + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.8", "bundled": true, "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" } }, "npmlog": { @@ -4662,8 +4339,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4675,7 +4351,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4709,33 +4384,25 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "dev": true, "optional": true }, "rc": { - "version": "1.2.6", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "~0.4.0", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } } }, "readable-stream": { - "version": "2.3.6", + "version": "2.3.7", "bundled": true, "dev": true, "optional": true, @@ -4750,19 +4417,18 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.7.1", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4777,7 +4443,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.1", "bundled": true, "dev": true, "optional": true @@ -4798,7 +4464,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4818,7 +4483,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4830,18 +4494,18 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.13", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -4851,32 +4515,30 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -4885,11 +4547,15 @@ "rimraf": "2" } }, + "fullcalendar": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-3.10.1.tgz", + "integrity": "sha512-E0ioaHVmwdS4es8pNTUNva7505wPkUMFdn9JGFLYo+J12ARhN3zDBwoPj2DfB8rL7Yc1sSve+FqDHC3s2SZ7Fw==" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gauge": { "version": "2.7.4", @@ -4930,44 +4596,25 @@ } }, "gaze": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", - "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, "requires": { "globule": "^1.0.0" } }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { + "get-assigned-identifiers": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" }, "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, - "get-proxy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", - "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=", - "dev": true, - "requires": { - "rc": "^1.1.2" - } - }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -4991,31 +4638,12 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "gifsicle": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-3.0.4.tgz", - "integrity": "sha1-9Fy17RAWW2ZdySng6TKLbIId+js=", - "dev": true, - "requires": { - "bin-build": "^2.0.0", - "bin-wrapper": "^3.0.0", - "logalot": "^2.0.0" } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", - "dev": true, + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5025,42 +4653,6 @@ "path-is-absolute": "^1.0.0" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -5082,186 +4674,48 @@ } } }, - "glob-stream": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", - "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^5.0.3", - "glob-parent": "^3.0.0", - "micromatch": "^2.3.7", - "ordered-read-streams": "^0.3.0", - "through2": "^0.6.0", - "to-absolute-glob": "^0.1.1", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - } - } - }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, "requires": { "array-union": "^1.0.1", "glob": "^7.0.3", "object-assign": "^4.0.1", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "globs": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globs/-/globs-0.1.4.tgz", - "integrity": "sha1-HRNjn2F05K5zp/k22n2aB59lfBw=", + "integrity": "sha512-D23dWbOq48vlOraoSigbcQV4tWrnhwk+E/Um2cMuDS3/5dwGmdFeA7L/vAvDhLFlQOTDqHcXh35m/71g2A2WzQ==", "dev": true, "requires": { "glob": "^7.1.1" } }, "globule": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", - "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.4", + "lodash": "~4.17.12", "minimatch": "~3.0.2" } }, - "glogg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", - "integrity": "sha1-3PdY5EeJzD89MsHzVio2duajSBA=", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, "got": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", - "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", "requires": { "@sindresorhus/is": "^0.7.0", "cacheable-request": "^2.1.1", @@ -5282,23 +4736,17 @@ "url-to-options": "^1.0.1" }, "dependencies": { - "p-cancelable": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "growly": { "version": "1.3.0", @@ -5306,160 +4754,32 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, - "gulp-decompress": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz", - "integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=", - "dev": true, - "requires": { - "archive-type": "^3.0.0", - "decompress": "^3.0.0", - "gulp-util": "^3.0.1", - "readable-stream": "^2.0.2" - } - }, - "gulp-rename": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz", - "integrity": "sha1-OtRCh2PwXidk3sHGfYaNsnVoeBc=", - "dev": true - }, - "gulp-sourcemaps": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", - "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", - "dev": true, - "requires": { - "convert-source-map": "^1.1.1", - "graceful-fs": "^4.1.2", - "strip-bom": "^2.0.0", - "through2": "^2.0.0", - "vinyl": "^1.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "dependencies": { - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "^1.0.0" - } - }, "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "function-bind": "^1.0.2" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -5477,24 +4797,21 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, "has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha1-FAn5i8ACR9pF2mfO4KNvKC/yZFU=" + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true }, "has-to-string-tag-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha1-oEWrOD17SyASoAFIqwql8pAETU0=", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "requires": { "has-symbol-support-x": "^1.4.1" } @@ -5541,7 +4858,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -5554,50 +4870,30 @@ "dev": true }, "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" + "minimalistic-assert": "^1.0.1" } }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -5609,9 +4905,9 @@ } }, "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, "hpack.js": { @@ -5627,15 +4923,15 @@ } }, "html-comment-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", - "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", "dev": true }, "html-entities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", "dev": true }, "html-loader": { @@ -5652,18 +4948,18 @@ } }, "html-minifier": { - "version": "3.5.15", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.15.tgz", - "integrity": "sha512-OZa4rfb6tZOZ3Z8Xf0jKxXkiDcFWldQePGYFDcgKqES2sXeWaEv9y6QQvWUtX3ySI3feApQi5uCsHLINQ6NoAw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "dev": true, "requires": { "camel-case": "3.0.x", - "clean-css": "4.1.x", - "commander": "2.15.x", - "he": "1.1.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", "param-case": "2.1.x", "relateurl": "0.2.x", - "uglify-js": "3.3.x" + "uglify-js": "3.4.x" }, "dependencies": { "source-map": { @@ -5673,21 +4969,39 @@ "dev": true }, "uglify-js": { - "version": "3.3.23", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.23.tgz", - "integrity": "sha512-Ks+KqLGDsYn4z+pU7JsKCzC0T3mPYl+rU+VcPZiQOazjE4Uqi4UCRY3qPMDbJi7ze37n1lDXj3biz1ik93vqvw==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", "dev": true, "requires": { - "commander": "~2.15.0", + "commander": "~2.19.0", "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + } } } } }, + "html2canvas": { + "version": "0.5.0-beta4", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-0.5.0-beta4.tgz", + "integrity": "sha1-goLGKsX9eBaPVwK15IdxV8qT854=" + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=" + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" }, "http-deceiver": { "version": "1.2.7", @@ -5696,163 +5010,61 @@ "dev": true }, "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } } }, "http-parser-js": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.12.tgz", - "integrity": "sha1-uc+/Sizybw/DSxDKFImid3HjR08=", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", "dev": true }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "http-proxy-middleware": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", - "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", "dev": true, "requires": { - "http-proxy": "^1.16.2", - "is-glob": "^3.1.0", - "lodash": "^4.17.2", - "micromatch": "^2.3.11" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - } - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - } + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" } }, "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^0.2.0", + "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } @@ -5860,8 +5072,7 @@ "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "icheck": { "version": "1.0.2", @@ -5869,10 +5080,13 @@ "integrity": "sha1-BtCNo9R65EjBU7Jjm4bprX/fcSg=" }, "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=", - "dev": true + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } }, "icss-replace-symbols": { "version": "1.1.0", @@ -5890,10 +5104,9 @@ } }, "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", - "dev": true + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "iferr": { "version": "0.1.5", @@ -5911,7 +5124,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-5.3.1.tgz", "integrity": "sha1-8Zwu7h5xumxlWMUV+fyWaAGJptQ=", - "dev": true, "requires": { "file-type": "^4.1.0", "globby": "^6.1.0", @@ -5919,214 +5131,49 @@ "p-pipe": "^1.1.0", "pify": "^2.3.0", "replace-ext": "^1.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "imagemin-gifsicle": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-5.2.0.tgz", - "integrity": "sha1-N4FSTEV2Eu8EkWrzQkGitCv8tAo=", - "dev": true, - "requires": { - "exec-buffer": "^3.0.0", - "gifsicle": "^3.0.0", - "is-gif": "^1.0.0" - } - }, - "imagemin-mozjpeg": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/imagemin-mozjpeg/-/imagemin-mozjpeg-7.0.0.tgz", - "integrity": "sha1-2SZHf8bvXzp2ikIi97LYCNPrpWg=", - "dev": true, - "requires": { - "execa": "^0.8.0", - "is-jpg": "^1.0.0", - "mozjpeg": "^5.0.0" - }, - "dependencies": { - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "imagemin-optipng": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-5.2.1.tgz", - "integrity": "sha1-0i2kEsCfX/AKQzmWC5ioix2+hpU=", - "dev": true, - "requires": { - "exec-buffer": "^3.0.0", - "is-png": "^1.0.0", - "optipng-bin": "^3.0.0" - } - }, - "imagemin-pngquant": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/imagemin-pngquant/-/imagemin-pngquant-5.1.0.tgz", - "integrity": "sha1-uetWPZ5qOHb2JIvgBhuhsO8mnAc=", - "dev": true, - "requires": { - "execa": "^0.10.0", - "is-png": "^1.0.0", - "is-stream": "^1.1.0", - "pngquant-bin": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha1-/0Vqj1P5D47MxxqW0Rvfx/CCy1A=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "imagemin-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-6.0.0.tgz", - "integrity": "sha1-LdjIKUa+Qqjiy8rjxb8Ae8K4ueg=", - "dev": true, - "requires": { - "buffer-from": "^0.1.1", - "is-svg": "^2.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "buffer-from": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", - "integrity": "sha1-FfS5vO8BIETfMRQsFDM8r24CYNA=", - "dev": true - }, - "coa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.1.tgz", - "integrity": "sha1-8/iwsVBz411wJj+xBCyywCPbOK8=", - "dev": true, - "requires": { - "q": "^1.1.2" - } - }, - "csso": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.0.tgz", - "integrity": "sha512-WtJjFP3ZsSdWhiZr4/k1B9uHPgYjFYnDxfbaJxk1hz5PDLIJ5BCRWkJqaztZ0DbP8d2ZIVwUPIJb2YmCwkPaMw==", - "dev": true, - "requires": { - "css-tree": "1.0.0-alpha.27" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.27", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.27.tgz", - "integrity": "sha512-BAYp9FyN4jLXjfvRpTDchBllDptqlK9I7OsagXCG9Am5C+5jc8eRZHgqb9x500W2OKS14MMlpQc/nmh/aA7TEQ==", - "dev": true, - "requires": { - "mdn-data": "^1.0.0", - "source-map": "^0.5.3" - } - } - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - }, - "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha1-LnhEFka9RoLpY/IrbpKCPDCcYtw=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "svgo": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.0.5.tgz", - "integrity": "sha1-cEA2TAYqBTirrP9EAc6momp6OJo=", - "dev": true, - "requires": { - "coa": "~2.0.1", - "colors": "~1.1.2", - "css-select": "~1.3.0-rc0", - "css-select-base-adapter": "~0.1.0", - "css-tree": "1.0.0-alpha25", - "css-url-regex": "^1.1.0", - "csso": "^3.5.0", - "js-yaml": "~3.10.0", - "mkdirp": "~0.5.1", - "object.values": "^1.0.4", - "sax": "~1.2.4", - "stable": "~0.1.6", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - } } }, "img-loader": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/img-loader/-/img-loader-2.0.1.tgz", - "integrity": "sha1-3o+Aql4yIvoetMjDvD1B5djdfHg=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/img-loader/-/img-loader-3.0.1.tgz", + "integrity": "sha512-0jDJqexgzOuq3zlXwFTBKJlMcaP1uXyl5t4Qu6b1IgXb3IwBDjPfVylBC8vHFIIESDw/S+5QkBbtBrt4T8wESA==", "dev": true, "requires": { - "imagemin": "^5.3.1", - "imagemin-gifsicle": "^5.2.0", - "imagemin-mozjpeg": "^7.0.0", - "imagemin-optipng": "^5.2.0", - "imagemin-pngquant": "^5.0.1", - "imagemin-svgo": "^6.0.0", "loader-utils": "^1.1.0" } }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, "import-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha1-Xk/9wD9P5sAJxnKb6yljHC+CJ7w=", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", "dev": true, "requires": { "pkg-dir": "^2.0.0", @@ -6140,9 +5187,9 @@ "dev": true }, "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==", "dev": true }, "indent-string": { @@ -6160,32 +5207,49 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", - "dev": true + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "~0.5.3" + } + }, + "inputmask": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/inputmask/-/inputmask-3.3.11.tgz", + "integrity": "sha1-FCHJSuKMPc0bTSYze1CLs0mY4tg=" + }, + "insert-module-globals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", + "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", + "requires": { + "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } }, "internal-ip": { "version": "1.2.0", @@ -6197,9 +5261,9 @@ } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, "into-stream": { @@ -6212,9 +5276,9 @@ } }, "invariant": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz", - "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { "loose-envify": "^1.0.0" @@ -6226,33 +5290,28 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, + "ion-rangeslider": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/ion-rangeslider/-/ion-rangeslider-2.3.1.tgz", + "integrity": "sha512-6V+24FD13/feliI485gnRHZYD9Ev64M5NAFTxnVib516ATHa9PlXQrC+nOiPngouRYTCLPJyokAJEi3e1Umi5g==" + }, + "ionicons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-3.0.0.tgz", + "integrity": "sha1-QLja9P16MRUL0AIWD2ZJbiKpjDw=" + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, - "ip-regex": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", - "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=", - "dev": true - }, "ipaddr.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true }, - "is-absolute": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", - "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", - "dev": true, - "requires": { - "is-relative": "^0.1.0" - } - }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -6279,6 +5338,12 @@ } } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -6297,28 +5362,12 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-bzip2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz", - "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, "is-data-descriptor": { @@ -6342,15 +5391,15 @@ } }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -6361,7 +5410,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -6372,21 +5421,6 @@ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -6400,13 +5434,10 @@ "dev": true }, "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -6414,58 +5445,15 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-gif": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-1.0.0.tgz", - "integrity": "sha1-ptKumIkwB7/6l6HYwB1jIFgyCX4=", - "dev": true - }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, - "is-gzip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", - "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=", - "dev": true - }, - "is-jpg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-1.0.1.tgz", - "integrity": "sha1-KW1X/dmc4BBDSnKD40armhA16XU=", - "dev": true - }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, - "is-natural-number": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz", - "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=", - "dev": true - }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -6486,34 +5474,11 @@ } } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, "is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -6523,7 +5488,7 @@ "is-path-in-cwd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { "is-path-inside": "^1.0.0" @@ -6546,61 +5511,25 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" } }, - "is-png": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-png/-/is-png-1.1.0.tgz", - "integrity": "sha1-1XSxK/J1wDUEVVcLDltXqwYgd84=", - "dev": true - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dev": true, "requires": { - "has": "^1.0.1" + "has": "^1.0.3" } }, - "is-relative": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", - "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=", - "dev": true - }, "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, "is-stream": { "version": "1.1.0", @@ -6608,6 +5537,12 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, "is-svg": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", @@ -6618,44 +5553,29 @@ } }, "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true - }, - "is-tar": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", - "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha1-BKTfRtKMTP89c9Af8Gq+sxihqlI=", - "dev": true - }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, - "is-valid-glob": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", - "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=", - "dev": true - }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "is-wsl": { @@ -6664,12 +5584,6 @@ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, - "is-zip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", - "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6695,16 +5609,36 @@ "isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" } }, "jquery": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", - "integrity": "sha1-lYzinoHJeQ8xvneS311NlfxX+8o=" + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.0.tgz", + "integrity": "sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==" + }, + "jquery-form-validator": { + "version": "2.3.79", + "resolved": "https://registry.npmjs.org/jquery-form-validator/-/jquery-form-validator-2.3.79.tgz", + "integrity": "sha512-/jG1qy7FEcGFCGlnEst5pOn1SZi3awDxRrlGDHdBEnY8Ga5zXA00OnAKIZV8fUCpUTT003BPbFBDR7hlgOsN8w==", + "requires": { + "jquery": "2.2.4" + }, + "dependencies": { + "jquery": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz", + "integrity": "sha1-LInWiJterFIqfuoywUUhVZxsvwI=" + } + } + }, + "jquery-knob": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/jquery-knob/-/jquery-knob-1.2.11.tgz", + "integrity": "sha1-83w528HHpqbBLNsu1Pa/+2g/ENY=" }, "jquery-slimscroll": { "version": "1.3.8", @@ -6714,6 +5648,11 @@ "jquery": ">= 1.7" } }, + "jquery-sparkline": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jquery-sparkline/-/jquery-sparkline-2.4.0.tgz", + "integrity": "sha1-G+i3twTdOFcVJwiu+x1KSzpp+zM=" + }, "jquery-ui": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.12.1.tgz", @@ -6730,9 +5669,9 @@ "integrity": "sha1-mKuuhb6s4cw2JkXnqHNg/5QYF18=" }, "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==", "dev": true }, "js-tokens": { @@ -6754,8 +5693,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsesc": { "version": "0.5.0", @@ -6771,7 +5709,13 @@ "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", - "integrity": "sha1-3KFKcCNf+C8KyaOr62DTN6NlGF0=", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "json-schema": { @@ -6780,15 +5724,14 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", "requires": { "jsonify": "~0.0.0" } @@ -6799,15 +5742,18 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", "dev": true }, "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } }, "jsonfile": { "version": "3.0.1", @@ -6821,14 +5767,38 @@ "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "jspdf": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-1.3.4.tgz", + "integrity": "sha1-j0uu3Rj1wkYPAQdijHiYxgarKW8=", + "requires": { + "cf-blob.js": "0.0.1" + }, + "dependencies": { + "adler32cs": { + "version": "github:chick307/adler32cs.js#7fd00ffa24bf173a1eeb987ce7a21ae214eff658", + "from": "github:chick307/adler32cs.js#7fd00ffa24bf173a1eeb987ce7a21ae214eff658" + }, + "filesaver.js": { + "version": "github:andyinabox/FileSaver.js#973b433b8fbaee9a11d53b9ae423b046742cfe32", + "from": "github:andyinabox/FileSaver.js#973b433b8fbaee9a11d53b9ae423b046742cfe32" + } + } + }, + "jspdf-autotable": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-2.0.17.tgz", + "integrity": "sha1-usPRFK4S1E4NeXVjTROZ+GZxbHc=", + "requires": { + "jspdf": "^1.0.272" + } }, "jsprim": { "version": "1.4.1", @@ -6839,39 +5809,49 @@ "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } + } + }, + "jvectormap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jvectormap/-/jvectormap-1.2.2.tgz", + "integrity": "sha1-LkQIskpgRz/xBsHnJD43WuXKhdo=", + "requires": { + "jquery": ">=1.5" } }, "keyv": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha1-RJI7o55osSp87H32wyaMAx8u83M=", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", "requires": { "json-buffer": "3.0.0" } }, "killable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", - "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", "dev": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "requires": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, "laravel-mix": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-2.1.11.tgz", - "integrity": "sha1-N0G94hRYb4wXFkGZDJpIfuzlNn0=", + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-2.1.14.tgz", + "integrity": "sha512-M/Vzgr6+QQGukciAQ91SZvOhUyrPm41bq/nRyF2j2HR8/g3vzvTQbRkdTGOpq9Z+y3REEj8qR2A3ScnEG37Dgw==", "dev": true, "requires": { "autoprefixer": "^7.2.6", @@ -6880,7 +5860,7 @@ "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.5.1", - "chokidar": "^2.0.0", + "chokidar": "^2.0.3", "clean-css": "^4.1.3", "concatenate": "0.0.2", "css-loader": "^0.28.9", @@ -6892,10 +5872,10 @@ "fs-extra": "^3.0.1", "glob": "^7.1.2", "html-loader": "^0.4.5", - "img-loader": "^2.0.1", + "img-loader": "^3.0.0", "lodash": "^4.17.5", "md5": "^2.2.1", - "node-sass": "^4.7.2", + "node-sass": "^4.9.0", "postcss-loader": "^2.1.0", "resolve-url-loader": "^2.2.1", "sass-loader": "^6.0.5", @@ -6913,9 +5893,9 @@ }, "dependencies": { "vue-template-compiler": { - "version": "2.5.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz", - "integrity": "sha1-k7SFcOVscgzfPwUcwVKHwm+9BMs=", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz", + "integrity": "sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==", "dev": true, "requires": { "de-indent": "^1.0.2", @@ -6930,21 +5910,6 @@ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true }, - "lazy-req": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lazy-req/-/lazy-req-1.1.0.tgz", - "integrity": "sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=", - "dev": true - }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - } - }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -6956,7 +5921,7 @@ }, "less": { "version": "github:less/less.js#efa6eb5306f28a7ef7e235d79ce854b780345591", - "from": "less@github:less/less.js#efa6eb5306f28a7ef7e235d79ce854b780345591", + "from": "github:less/less.js#efa6eb5306f28a7ef7e235d79ce854b780345591", "requires": { "errno": "^0.1.1", "graceful-fs": "^4.1.2", @@ -6966,178 +5931,23 @@ "promise": "^7.1.1", "request": "^2.83.0", "source-map": "^0.5.3" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "optional": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "optional": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "optional": true - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "optional": true, - "requires": { - "hoek": "4.x.x" - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "optional": true, - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "optional": true, - "requires": { - "hoek": "4.x.x" - } - } - } - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "optional": true - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "optional": true, - "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "optional": true, - "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "optional": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "optional": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "optional": true - }, - "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", - "optional": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "optional": true, - "requires": { - "hoek": "4.x.x" - } - } } }, "less-loader": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.1.0.tgz", - "integrity": "sha1-LBNSxbCaT4QQFJAnT9UWdN5BNj4=", + "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==", "requires": { "clone": "^2.1.1", "loader-utils": "^1.1.0", "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } } }, "list.js": { @@ -7159,30 +5969,22 @@ "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "strip-bom": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" } }, "locate-path": { @@ -7196,9 +5998,9 @@ } }, "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "lodash._baseassign": { @@ -7217,18 +6019,6 @@ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", "dev": true }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, "lodash._bindcallback": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", @@ -7258,30 +6048,6 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", @@ -7294,27 +6060,12 @@ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -7327,12 +6078,6 @@ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", @@ -7345,16 +6090,9 @@ } }, "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.mergewith": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", - "integrity": "sha1-Y5BX5ybDr72z59QnQcqo1uQzWSc=", - "dev": true + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" }, "lodash.restparam": { "version": "3.6.1", @@ -7368,53 +6106,16 @@ "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", "dev": true }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, - "logalot": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", - "integrity": "sha1-X46MkNME7fElMJUaVVSruMXj9VI=", - "dev": true, - "requires": { - "figures": "^1.3.5", - "squeak": "^1.0.0" - } - }, "loglevel": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", - "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz", + "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==", "dev": true }, "longest": { @@ -7424,12 +6125,12 @@ "dev": true }, "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "loud-rejection": { @@ -7449,45 +6150,33 @@ "dev": true }, "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" - }, - "lpad-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz", - "integrity": "sha1-IfYArBwwlcPG5JfuZyce4ISB/p4=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "indent-string": "^2.1.0", - "longest": "^1.0.0", - "meow": "^3.3.0" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, - "macaddress": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", - "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", - "dev": true - }, "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "requires": { "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } } }, "map-cache": { @@ -7512,9 +6201,9 @@ } }, "math-expression-evaluator": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", - "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz", + "integrity": "sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ==", "dev": true }, "md5": { @@ -7529,21 +6218,15 @@ } }, "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "mdn-data": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.2.tgz", - "integrity": "sha512-HUqqf4U+XdKomJXe2Chw+b1zPXFRUZ3bfUbrGLQ2TGwMOBRULuTHI9geusGqRL4WzsusnLLxYAxV4f/F/8wV+g==", - "dev": true - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7585,14 +6268,6 @@ "read-pkg-up": "^1.0.1", "redent": "^1.0.0", "trim-newlines": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "merge-descriptors": { @@ -7601,15 +6276,6 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -7619,7 +6285,7 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -7640,8 +6306,7 @@ "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", - "dev": true, + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -7653,59 +6318,56 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.43.0" } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mississippi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha1-NEKlCPr8KFAEhv7qmUCWduTuWm8=", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", "dev": true, "requires": { "concat-stream": "^1.5.0", @@ -7718,24 +6380,12 @@ "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -7745,7 +6395,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -7772,13 +6422,50 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, + "mkdirp-classic": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz", + "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g==" + }, + "module-deps": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.2.tgz", + "integrity": "sha512-a9y6yDv5u5I4A+IPHTnqFxcaKr4p50/zxTjcQJaX2ws9tN/W6J6YXnEKhqRyPhl494dkcxx951onSKVezmI+3w==", + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^1.7.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "morris.js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/morris.js/-/morris.js-0.5.0.tgz", + "integrity": "sha1-cldnE1z64Fmq51mZuyzmocXRtEs=" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -7793,17 +6480,6 @@ "run-queue": "^1.0.3" } }, - "mozjpeg": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-5.0.0.tgz", - "integrity": "sha1-uGccSSRWijY94AP/L9OXq4P3UsU=", - "dev": true, - "requires": { - "bin-build": "^2.2.0", - "bin-wrapper": "^3.0.0", - "logalot": "^2.0.0" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -7813,7 +6489,7 @@ "multicast-dns": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "dev": true, "requires": { "dns-packet": "^1.3.1", @@ -7826,60 +6502,16 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha1-ltDNYQ69WNS03pzAxoKM2pnHVI8=", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true }, "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -7887,7 +6519,6 @@ "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", @@ -7897,15 +6528,15 @@ } }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, "neo-async": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", - "integrity": "sha1-rLkJ4yex6H7J7xX0G4omlRKtQe4=", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, "next-tick": { @@ -7915,41 +6546,40 @@ "dev": true }, "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha1-2Tli9sUvLBVYwPvabVEoGfHv4cQ=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, "requires": { "lower-case": "^1.1.1" } }, "node-forge": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz", - "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", "dev": true }, "node-gyp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", - "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", "dev": true, "requires": { "fstream": "^1.0.0", "glob": "^7.0.3", "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", "mkdirp": "^0.5.0", "nopt": "2 || 3", "npmlog": "0 || 1 || 2 || 3 || 4", "osenv": "0", - "request": "2", + "request": "^2.87.0", "rimraf": "2", "semver": "~5.3.0", "tar": "^2.0.0", @@ -7965,9 +6595,9 @@ } }, "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha1-X5QmPUBPbkR2fXJpAf/wVHjWAN8=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "requires": { "assert": "^1.1.1", @@ -7977,10 +6607,10 @@ "constants-browserify": "^1.0.0", "crypto-browserify": "^3.11.0", "domain-browser": "^1.1.1", - "events": "^1.0.0", + "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", + "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", @@ -7991,45 +6621,91 @@ "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", "url": "^0.11.0", - "util": "^0.10.3", - "vm-browserify": "0.0.4" + "util": "^0.11.0", + "vm-browserify": "^1.0.1" }, "dependencies": { - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha1-yrHmEY8FEJXli1KBrqjBzSK/wOM=", - "dev": true - }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } + }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } } } }, "node-notifier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", - "integrity": "sha1-+jE90I9VF9sOJQLldY1mSsafneo=", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", "dev": true, "requires": { "growly": "^1.3.0", - "semver": "^5.4.1", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" } }, "node-sass": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", - "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -8039,26 +6715,18 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash.assign": "^4.2.0", - "lodash.clonedeep": "^4.3.2", - "lodash.mergewith": "^4.6.0", + "lodash": "^4.17.15", "meow": "^3.7.0", "mkdirp": "^0.5.1", - "nan": "^2.10.0", - "node-gyp": "^3.3.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "~2.79.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, "dependencies": { - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true - }, "cross-spawn": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", @@ -8068,67 +6736,9 @@ "lru-cache": "^4.0.1", "which": "^1.2.9" } - }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, - "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true - }, - "request": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", - "dev": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1", - "uuid": "^3.0.0" - } - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true } } }, - "node-status-codes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", - "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=", - "dev": true - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -8139,25 +6749,22 @@ } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "normalize-range": { "version": "0.1.2", @@ -8175,16 +6782,6 @@ "sort-keys": "^2.0.0" } }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha1-JWzEe9DiGMJZxOlVC/QTvCGSr/k=", - "dev": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -8197,7 +6794,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -8206,15 +6803,6 @@ "set-blocking": "~2.0.0" } }, - "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", @@ -8228,9 +6816,9 @@ "dev": true }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", @@ -8268,10 +6856,26 @@ } } }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-path": { @@ -8289,24 +6893,16 @@ "isobject": "^3.0.0" } }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "object.pick": { @@ -8318,22 +6914,10 @@ "isobject": "^3.0.1" } }, - "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" - } - }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, "on-finished": { @@ -8346,88 +6930,41 @@ } }, "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, "opn": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", - "integrity": "sha1-ZIcVZchjh18FLP31PT48ta21Oxw=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "dev": true, "requires": { "is-wsl": "^1.1.0" } }, - "optipng-bin": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-3.1.4.tgz", - "integrity": "sha1-ldNPLEiHBPb9cGBr/qDGWfHZXYQ=", - "dev": true, - "requires": { - "bin-build": "^2.0.0", - "bin-wrapper": "^3.0.0", - "logalot": "^2.0.0" - } - }, - "ordered-read-streams": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", - "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", - "dev": true, - "requires": { - "is-stream": "^1.0.1", - "readable-stream": "^2.0.1" - } - }, "original": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "dev": true, "requires": { - "url-parse": "1.0.x" - }, - "dependencies": { - "url-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", - "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", - "dev": true, - "requires": { - "querystringify": "0.0.x", - "requires-port": "1.0.x" - } - } + "url-parse": "^1.4.3" } }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-filter-obj": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-1.0.3.tgz", - "integrity": "sha1-WRUzDZDs7VV9LZOKMcbdIU2cY60=", - "dev": true + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, "os-homedir": { "version": "1.0.2", @@ -8453,7 +6990,7 @@ "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "requires": { "os-homedir": "^1.0.0", @@ -8461,30 +6998,9 @@ } }, "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo=", - "dev": true - }, - "p-event": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", - "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", - "dev": true, - "requires": { - "p-timeout": "^1.1.1" - }, - "dependencies": { - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - } - } + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" }, "p-finally": { "version": "1.0.0", @@ -8497,9 +7013,9 @@ "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -8517,29 +7033,13 @@ "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, - "p-map-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz", - "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, "p-pipe": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz", - "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=", - "dev": true - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true + "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=" }, "p-timeout": { "version": "2.0.1", @@ -8555,24 +7055,31 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "pace": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/pace/-/pace-0.0.4.tgz", + "integrity": "sha1-1mQF1fW8EtJUQabibIeNvGnnenc=", + "requires": { + "charm": "~0.1.0" + } + }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha1-AQEhG6pwxLykoPY/Igbpe3368lg=", - "dev": true + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "papaparse": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-4.4.0.tgz", - "integrity": "sha1-a829qAhz4Az7C9zXpFcccqmkAWg=" + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-4.6.3.tgz", + "integrity": "sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ==" }, "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "cyclist": "~0.2.2", + "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } @@ -8586,46 +7093,25 @@ "no-case": "^2.2.0" } }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "~0.11.15" + } + }, "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha1-9r8pOBgzK9DatU77Fgh3JHRebKg=", - "dev": true, + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-json": { @@ -8638,9 +7124,9 @@ } }, "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "pascalcase": { @@ -8650,10 +7136,9 @@ "dev": true }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" }, "path-dirname": { "version": "1.0.2", @@ -8670,8 +7155,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -8686,10 +7170,14 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" }, "path-to-regexp": { "version": "0.1.7", @@ -8706,21 +7194,12 @@ "graceful-fs": "^4.1.2", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha1-dAQgjsawG2LYW/g4U6gGT42cKlw=", - "dev": true, + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -8729,34 +7208,25 @@ "sha.js": "^2.4.8" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -8770,358 +7240,31 @@ "find-up": "^2.1.0" } }, - "pngquant-bin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pngquant-bin/-/pngquant-bin-4.0.0.tgz", - "integrity": "sha1-RorfcDb1D64JycJk72K20QwC9cI=", - "dev": true, - "requires": { - "bin-build": "^3.0.0", - "bin-wrapper": "^3.0.0", - "execa": "^0.10.0", - "logalot": "^2.0.0" - }, - "dependencies": { - "bin-build": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", - "integrity": "sha1-xXgKJaip+WbYJEIX5sH1CCoUOGE=", - "dev": true, - "requires": { - "decompress": "^4.0.0", - "download": "^6.2.2", - "execa": "^0.7.0", - "p-map-series": "^1.0.0", - "tempfile": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - } - } - }, - "caw": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", - "integrity": "sha1-bDygcfwZRyCIPC3F2psHS/x+npU=", - "dev": true, - "requires": { - "get-proxy": "^2.0.0", - "isurl": "^1.0.0-alpha5", - "tunnel-agent": "^0.6.0", - "url-to-options": "^1.0.1" - } - }, - "decompress": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", - "dev": true, - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - } - }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha1-cYy9P8sWIJcW5womuE57pFkuWvE=", - "dev": true, - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha1-MIKluIDqQEOBY0nzeLVsUWvho5s=", - "dev": true, - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha1-5QzXXTVv/tTjBtxPW89Sp5kDqRk=", - "dev": true - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha1-wJvDXE0R894J8tLaU+neI+fOHu4=", - "dev": true, - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "dev": true, - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true - } - } - }, - "download": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", - "integrity": "sha1-rNalQuTNC7Qspwz8mMnkOwcDlxQ=", - "dev": true, - "requires": { - "caw": "^2.0.0", - "content-disposition": "^0.5.2", - "decompress": "^4.0.0", - "ext-name": "^5.0.0", - "file-type": "5.2.0", - "filenamify": "^2.0.0", - "get-stream": "^3.0.0", - "got": "^7.0.0", - "make-dir": "^1.0.0", - "p-event": "^1.0.0", - "pify": "^3.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha1-/0Vqj1P5D47MxxqW0Rvfx/CCy1A=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - } - } - }, - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true - }, - "filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", - "dev": true - }, - "filenamify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.0.0.tgz", - "integrity": "sha1-vRYiYsC26Uv7zc8Zo7uzdk94VpU=", - "dev": true, - "requires": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.0", - "trim-repeated": "^1.0.0" - } - }, - "get-proxy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", - "integrity": "sha1-NJ8rTZHUTE1NTpy6KtkBQ/rF75M=", - "dev": true, - "requires": { - "npm-conf": "^1.1.0" - } - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - }, - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=", - "dev": true, - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - } - } - }, - "is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", - "dev": true - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha1-SYdzYmT8NEzyD2w0rKnRPR1O1sU=", - "dev": true, - "requires": { - "is-natural-number": "^4.0.1" - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - } - } - }, "portfinder": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", - "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", "dev": true, "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" }, "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -9132,14 +7275,14 @@ "dev": true }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "^2.3.1", + "chalk": "^2.4.1", "source-map": "^0.6.1", - "supports-color": "^5.2.0" + "supports-color": "^5.4.0" }, "dependencies": { "ansi-styles": { @@ -9152,9 +7295,9 @@ } }, "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -9169,9 +7312,9 @@ "dev": true }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -9199,7 +7342,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9239,7 +7382,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9278,7 +7421,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9316,7 +7459,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9354,7 +7497,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9392,7 +7535,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9430,7 +7573,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9469,7 +7612,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9490,13 +7633,12 @@ } }, "postcss-filter-plugins": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", - "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz", + "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==", "dev": true, "requires": { - "postcss": "^5.0.4", - "uniqid": "^4.0.0" + "postcss": "^5.0.4" }, "dependencies": { "has-flag": { @@ -9529,15 +7671,13 @@ } }, "postcss-load-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", - "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", "dev": true, "requires": { - "cosmiconfig": "^2.1.0", - "object-assign": "^4.1.0", - "postcss-load-options": "^1.2.0", - "postcss-load-plugins": "^2.3.0" + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" } }, "postcss-load-options": { @@ -9548,6 +7688,23 @@ "requires": { "cosmiconfig": "^2.1.0", "object-assign": "^4.1.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + } } }, "postcss-load-plugins": { @@ -9558,36 +7715,41 @@ "requires": { "cosmiconfig": "^2.1.1", "object-assign": "^4.1.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + } } }, "postcss-loader": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.4.tgz", - "integrity": "sha512-L2p654oK945B/gDFUGgOhh7uzj19RWoY1SVMeJVoKno1H2MdbQ0RppR/28JGju4pMb22iRC7BJ9aDzbxXSLf4A==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.6.tgz", + "integrity": "sha512-hgiWSc13xVQAq25cVw80CH0l49ZKlAnU1hKPOdRrNj89bokRr/bZF2nT+hebPPF9c9xs8c3gw3Fr2nxtmXYnNg==", "dev": true, "requires": { "loader-utils": "^1.1.0", "postcss": "^6.0.0", - "postcss-load-config": "^1.2.0", + "postcss-load-config": "^2.0.0", "schema-utils": "^0.4.0" }, "dependencies": { - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } - }, "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "dev": true, "requires": { "ajv": "^6.1.0", @@ -9616,7 +7778,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9654,7 +7816,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9706,7 +7868,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9752,7 +7914,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9791,7 +7953,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9832,7 +7994,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9873,7 +8035,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -9894,9 +8056,9 @@ } }, "postcss-modules-extract-imports": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", - "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", "dev": true, "requires": { "postcss": "^6.0.1" @@ -9950,7 +8112,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10003,7 +8165,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10067,7 +8229,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10106,7 +8268,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10144,7 +8306,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10184,7 +8346,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10236,7 +8398,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10276,7 +8438,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10297,9 +8459,9 @@ } }, "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, "postcss-zindex": { @@ -10322,7 +8484,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -10347,39 +8509,37 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, - "prettier": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", - "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==", - "dev": true + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "dev": true }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "optional": true, "requires": { "asap": "~2.0.3" @@ -10391,20 +8551,14 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, "proxy-addr": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", - "integrity": "sha1-NV8mJQWmIWRrMTCnKOtkfiIFU0E=", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", "dev": true, "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.6.0" + "ipaddr.js": "1.9.1" } }, "prr": { @@ -10418,23 +8572,28 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha1-RuuRByBr9zSJ+LhbadkTNMZhCZQ=", - "dev": true, + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -10442,12 +8601,12 @@ } }, "pumpify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", - "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "^3.5.3", + "duplexify": "^3.6.0", "inherits": "^2.0.3", "pump": "^2.0.0" } @@ -10464,10 +8623,9 @@ "dev": true }, "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "5.1.1", @@ -10482,47 +8640,23 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "querystringify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", - "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", "dev": true }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha1-0wLFIpSFiISKjTAMkytEwkIx2oA=", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" } @@ -10530,85 +8664,52 @@ "randomfill": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", - "dev": true, + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, + "raphael": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/raphael/-/raphael-2.3.0.tgz", + "integrity": "sha512-w2yIenZAQnp257XUWGni4bLMVxpUpcIl7qgxEgDIXtmSypYtlNxfXWpOBxs7LBTps5sDwhRnrToJrMUrivqNTQ==", + "requires": { + "eve-raphael": "0.5.0" + } + }, "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "dev": true, "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", - "dev": true - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "dev": true, - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - } - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true } } }, - "rc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", - "dev": true, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "read-all-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0", - "readable-stream": "^2.0.0" + "readable-stream": "^2.0.2" } }, "read-pkg": { @@ -10654,29 +8755,43 @@ } }, "readable-stream": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", - "integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "recast": { @@ -10729,38 +8844,39 @@ } }, "reduce-function-call": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", - "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", "dev": true, "requires": { - "balanced-match": "^0.4.2" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - } + "balanced-match": "^1.0.0" } }, "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha1-DDNtOYBVPXVcObWGrjsgqknIK38=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", "dev": true }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, "regenerator-transform": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha1-HkmWg3Ix2ot/PPQRTXG1aRoGgN0=", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", "dev": true, "requires": { "babel-runtime": "^6.18.0", @@ -10768,19 +8884,10 @@ "private": "^0.1.6" } }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", @@ -10788,11 +8895,21 @@ } }, "regex-parser": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.9.tgz", - "integrity": "sha1-o3L0WiSLYpdqVoA3wbbmCmBZkZI=", + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.10.tgz", + "integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==", "dev": true }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, "regexpu-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -10832,9 +8949,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -10855,37 +8972,33 @@ "replace-ext": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" }, "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" + "uuid": "^3.3.2" } }, "require-directory": { @@ -10913,12 +9026,11 @@ "dev": true }, "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz", + "integrity": "sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-cwd": { @@ -10943,9 +9055,9 @@ "dev": true }, "resolve-url-loader": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-2.3.0.tgz", - "integrity": "sha1-4bNwNNSPIvjPufBMAm+qoHD9ryY=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-2.3.2.tgz", + "integrity": "sha512-sc/UVgiADdoTc+4cGPB7cUCnlEkzlxD1NXHw4oa9qA0fp30H8mAQ2ePJBP9MQ029DUuhEPouhNdvzT37pBCV0g==", "dev": true, "requires": { "adjust-sourcemap-loader": "^1.1.0", @@ -10964,6 +9076,21 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true } } }, @@ -10978,7 +9105,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "rework": { @@ -11015,19 +9142,18 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", - "dev": true, + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -11043,9 +9169,9 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, "safe-regex": { "version": "1.1.0", @@ -11056,6 +9182,11 @@ "ret": "~0.1.10" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "sass-graph": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", @@ -11120,7 +9251,7 @@ "sass-loader": { "version": "6.0.7", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.7.tgz", - "integrity": "sha1-3S/bPn7v9KU/NbpqxAhxVIg1PQA=", + "integrity": "sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==", "dev": true, "requires": { "clone-deep": "^2.0.1", @@ -11128,12 +9259,20 @@ "lodash.tail": "^4.1.1", "neo-async": "^2.5.0", "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, "schema-utils": { @@ -11156,6 +9295,18 @@ "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.3.0" } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true } } }, @@ -11180,26 +9331,6 @@ } } }, - "seek-bzip": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", - "dev": true, - "requires": { - "commander": "~2.8.1" - }, - "dependencies": { - "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } - } - } - }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -11212,39 +9343,24 @@ "integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==" }, "selfsigned": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.2.tgz", - "integrity": "sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", "dev": true, "requires": { - "node-forge": "0.7.1" + "node-forge": "0.9.0" } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, - "semver-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz", - "integrity": "sha1-kqSWkGX5xwxpR1PVUkj8aPj2Usk=", - "dev": true - }, - "semver-truncate": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz", - "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", "dev": true, "requires": { "debug": "2.6.9", @@ -11254,35 +9370,43 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "range-parser": "~1.2.1", + "statuses": "~1.5.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } }, "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha1-GqM2FiyIqJDdrVOEuuvJOmVRYf4=", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", "dev": true }, "serve-index": { @@ -11303,24 +9427,48 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true } } }, "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "parseurl": "~1.3.3", + "send": "0.17.1" } }, "set-blocking": { @@ -11329,16 +9477,10 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -11365,16 +9507,15 @@ "dev": true }, "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", - "dev": true, + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -11383,7 +9524,7 @@ "shallow-clone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha1-RIDNBuiC72iyrYij6lSDLixItXE=", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", "dev": true, "requires": { "is-extendable": "^0.1.1", @@ -11394,11 +9535,28 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "requires": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -11414,28 +9572,49 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "slimscroll": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/slimscroll/-/slimscroll-0.9.1.tgz", + "integrity": "sha1-9nXNxgHYCtog8WAE0ifRVv0Rh7I=", + "requires": { + "browserify": ">=3.46.0", + "classie": ">=0.0.1", + "domhelper": "~0.9.0", + "util-extend": "^1.0.1" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", @@ -11451,7 +9630,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -11480,7 +9659,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", @@ -11500,7 +9679,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -11509,7 +9688,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -11518,7 +9697,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -11531,7 +9710,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -11548,19 +9727,10 @@ } } }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", - "integrity": "sha1-2Xa76ACve9IK4IWY1YI5NQiZPA0=", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", "dev": true, "requires": { "faye-websocket": "^0.10.0", @@ -11568,9 +9738,9 @@ } }, "sockjs-client": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", - "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", + "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", "dev": true, "requires": { "debug": "^2.6.6", @@ -11584,16 +9754,16 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "faye-websocket": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", - "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" @@ -11609,30 +9779,10 @@ "is-plain-obj": "^1.0.0" } }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", - "dev": true, - "requires": { - "sort-keys": "^1.0.0" - }, - "dependencies": { - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - } - } - }, "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha1-qqR0A/eyRakvvJfqCPJQ1gh+0IU=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, "source-map": { @@ -11641,12 +9791,12 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "dev": true, "requires": { - "atob": "^2.0.0", + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -11656,7 +9806,7 @@ "source-map-support": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { "source-map": "^0.5.6" @@ -11668,16 +9818,10 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, - "sparkles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", - "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", - "dev": true - }, "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -11685,15 +9829,15 @@ } }, "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -11701,58 +9845,79 @@ } }, "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, "requires": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", + "debug": "^4.1.0", + "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" + "spdy-transport": "^3.0.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, "spdy-transport": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.0.tgz", - "integrity": "sha1-S7sVqv/tC+791WrWHb3Iuj4st6E=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, "requires": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", + "debug": "^4.1.0", + "detect-node": "^2.0.4", "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } @@ -11760,7 +9925,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -11772,21 +9937,18 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "squeak": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz", - "integrity": "sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM=", - "dev": true, + "ssf": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz", + "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==", "requires": { - "chalk": "^1.0.0", - "console-stream": "^0.1.1", - "lpad-align": "^1.0.1" + "frac": "~1.1.2" } }, "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -11795,41 +9957,23 @@ "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "ssri": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha1-ujhyycbTOgcEp9cf8EXl7EiZnQY=", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "dev": true, "requires": { "safe-buffer": "^5.1.1" } }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", - "dev": true - }, "stackframe": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", - "integrity": "sha1-NXskqZL5Qny6a1RdlqFO0svKGHs=", - "dev": true - }, - "stat-mode": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", - "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.1.1.tgz", + "integrity": "sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ==", "dev": true }, "static-extend": { @@ -11854,25 +9998,24 @@ } }, "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "dev": true, "requires": { "readable-stream": "^2.0.1" } }, "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" @@ -11882,16 +10025,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" } }, "stream-each": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha1-joxGP5HaiZF3h2WHP+TZYNj2Fr0=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -11899,24 +10041,43 @@ } }, "stream-http": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", - "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.0.tgz", + "integrity": "sha512-cuB6RgO7BqC4FBYzmnvhob5Do3wIdIsXAgGycHJnW+981gHqoYcYz9lqjJrk8WXRddbwPuqPYRl+bag6mYv4lw==", "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", - "readable-stream": "^2.3.3", - "to-arraybuffer": "^1.0.0", + "readable-stream": "^3.0.6", "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -11930,7 +10091,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -11954,18 +10115,55 @@ } } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } }, "strip-ansi": { "version": "3.0.1", @@ -11985,38 +10183,6 @@ "is-utf8": "^0.2.0" } }, - "strip-bom-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", - "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "strip-bom": "^2.0.0" - } - }, - "strip-dirs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz", - "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=", - "dev": true, - "requires": { - "chalk": "^1.0.0", - "get-stdin": "^4.0.1", - "is-absolute": "^0.1.5", - "is-natural-number": "^2.0.0", - "minimist": "^1.1.0", - "sum-up": "^1.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -12032,38 +10198,22 @@ "get-stdin": "^4.0.1" } }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.2" - } - }, "style-loader": { "version": "0.18.2", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.18.2.tgz", - "integrity": "sha1-zDFFmvvNbYC3Ig7lSykan9Zv9es=", + "integrity": "sha512-WPpJPZGUxWYHWIUMNNOYqql7zh85zGmr84FdTVWq52WTIkqlW9xSxD3QYWi/T31cqn9UNSsietVEgGn2aaSCzw==", "dev": true, "requires": { "loader-utils": "^1.0.2", "schema-utils": "^0.3.0" } }, - "sum-up": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", - "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", - "dev": true, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "requires": { - "chalk": "^1.0.0" + "minimist": "^1.1.0" } }, "supports-color": { @@ -12087,133 +10237,74 @@ "whet.extend": "~0.9.9" } }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "requires": { + "acorn-node": "^1.2.0" + } + }, + "tableexport.jquery.plugin": { + "version": "1.10.17", + "resolved": "https://registry.npmjs.org/tableexport.jquery.plugin/-/tableexport.jquery.plugin-1.10.17.tgz", + "integrity": "sha512-kjngUtfDvEvGI08UTaS0e/+nGN2TQzFZRekP2hQ84dYBU/IjxszKGuU/DeV14I7oOe5otibtCzxlxGt4YZ/1iw==", + "requires": { + "es6-promise": ">=4.2.4", + "file-saver": ">=1.2.0", + "html2canvas": ">=0.5.0-beta4", + "jquery": ">=1.9.1", + "jspdf": "1.3.2 - 1.3.4", + "jspdf-autotable": "2.0.14 || 2.0.17", + "xlsx": ">=0.12.5" + } + }, "tapable": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", - "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", "dev": true }, "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "dev": true, "requires": { "block-stream": "*", - "fstream": "^1.0.2", + "fstream": "^1.0.12", "inherits": "2" } }, - "tar-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", - "integrity": "sha512-lh2iAPG/BHNmN6WB9Ybdynk9rEJ5GD/dy4zscHmVlwa1dq2tpE+BH78i5vjYwYVWEaOXGBjzxr89aVACF17Cpw==", - "dev": true, - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.0.0", - "to-buffer": "^1.1.0", - "xtend": "^4.0.0" - } - }, - "temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true - }, - "tempfile": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", - "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", - "dev": true, - "requires": { - "temp-dir": "^1.0.0", - "uuid": "^3.0.1" - } - }, "tether": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/tether/-/tether-1.4.4.tgz", - "integrity": "sha1-ncbrKz5gHaIJj9Jk5/eosmTeESU=" + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/tether/-/tether-1.4.7.tgz", + "integrity": "sha512-Z0J1aExjoFU8pybVkQAo/vD2wfSO63r+XOPfWQMC5qtf1bI7IWqNk4MiyBcgvvnY8kqnY06dVdvwTK2S3PU/Fw==" }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "through2-filter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", - "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", - "dev": true, - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "thunky": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", - "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.2.0.tgz", + "integrity": "sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==", "dev": true }, "timed-out": { @@ -12222,32 +10313,11 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha1-HSjj0qrfHVpZlsTp+VYBzQU0gK4=", - "dev": true, + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", "requires": { - "setimmediate": "^1.0.4" - } - }, - "to-absolute-glob": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", - "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "process": "~0.11.0" } }, "to-arraybuffer": { @@ -12256,12 +10326,6 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true - }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -12291,7 +10355,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", @@ -12310,12 +10374,26 @@ "repeat-string": "^1.6.1" } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "punycode": "^1.4.1" + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } } }, "trim-newlines": { @@ -12324,15 +10402,6 @@ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, - "trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.2" - } - }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -12340,34 +10409,18 @@ "dev": true }, "true-case-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", - "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "dev": true, "requires": { - "glob": "^6.0.4" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "glob": "^7.1.2" } }, "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" }, "tunnel-agent": { "version": "0.6.0", @@ -12380,24 +10433,28 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true }, "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "~2.1.24" } }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uglify-js": { "version": "2.8.29", @@ -12449,9 +10506,9 @@ "optional": true }, "uglifyjs-webpack-plugin": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz", - "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", + "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", "dev": true, "requires": { "cacache": "^10.0.4", @@ -12464,18 +10521,6 @@ "worker-farm": "^1.5.2" }, "dependencies": { - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } - }, "commander": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", @@ -12483,9 +10528,9 @@ "dev": true }, "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "dev": true, "requires": { "ajv": "^6.1.0", @@ -12510,49 +10555,61 @@ } } }, - "unbzip2-stream": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", - "integrity": "sha1-c6AzpWe7veWWVLGTxE1Ip+T0PEc=", - "dev": true, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", "requires": { - "buffer": "^3.0.1", - "through": "^2.3.6" + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" } }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "uniq": { @@ -12561,15 +10618,6 @@ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", "dev": true }, - "uniqid": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", - "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", - "dev": true, - "requires": { - "macaddress": "^0.2.8" - } - }, "uniqs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", @@ -12577,37 +10625,27 @@ "dev": true }, "unique-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, - "unique-stream": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", - "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", - "dev": true, - "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" - } - }, "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, "unpipe": { @@ -12616,12 +10654,6 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -12662,16 +10694,10 @@ } } }, - "unzip-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", - "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", - "dev": true - }, "upath": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.5.tgz", - "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "upper-case": { @@ -12681,19 +10707,17 @@ "dev": true }, "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", - "dev": true, + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" }, "dependencies": { "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", - "dev": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -12707,7 +10731,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -12716,27 +10739,18 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" } } }, "url-parse": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.0.tgz", - "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", "dev": true, "requires": { - "querystringify": "^2.0.0", + "querystringify": "^2.1.1", "requires-port": "^1.0.0" - }, - "dependencies": { - "querystringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", - "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", - "dev": true - } } }, "url-parse-lax": { @@ -12747,43 +10761,29 @@ "prepend-http": "^2.0.0" } }, - "url-regex": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", - "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", - "dev": true, - "requires": { - "ip-regex": "^1.0.1" - } - }, "url-to-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" }, "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true }, "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "requires": { - "inherits": "2.0.1" + "inherits": "2.0.3" }, "dependencies": { "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, @@ -12792,15 +10792,10 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } + "util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" }, "utils-merge": { "version": "1.0.1", @@ -12809,20 +10804,14 @@ "dev": true }, "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - }, - "vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", - "dev": true + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -12836,9 +10825,9 @@ "dev": true }, "vendors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", - "integrity": "sha1-f8te759WI7FWvOqJ7DfWNnbyGAE=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", "dev": true }, "verror": { @@ -12849,112 +10838,29 @@ "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "dependencies": { - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - } - } - }, - "vinyl-assign": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz", - "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "readable-stream": "^2.0.0" - } - }, - "vinyl-fs": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", - "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", - "dev": true, - "requires": { - "duplexify": "^3.2.0", - "glob-stream": "^5.3.2", - "graceful-fs": "^4.0.0", - "gulp-sourcemaps": "1.6.0", - "is-valid-glob": "^0.3.0", - "lazystream": "^1.0.0", - "lodash.isequal": "^4.0.0", - "merge-stream": "^1.0.0", - "mkdirp": "^0.5.0", - "object-assign": "^4.0.0", - "readable-stream": "^2.0.4", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^1.0.0", - "through2": "^2.0.0", - "through2-filter": "^2.0.0", - "vali-date": "^1.0.0", - "vinyl": "^1.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, "vue": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/vue/-/vue-2.4.4.tgz", - "integrity": "sha1-6pVQuWpxRl/SuLF7YWc7NWGGF4k=", + "integrity": "sha512-PCiRmc8ZT1DD5+BN8QUAmnkBefcCLfZVSuhc1u7iu5JoPrSHyyk/+4nehm7k2xVMi8+RFLk5WIHAN14UKF0txw==", "dev": true }, "vue-hot-reload-api": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz", - "integrity": "sha1-l5dhQkBdE9jvrhVHSeiMTjWM+SY=", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "dev": true }, "vue-loader": { - "version": "13.7.1", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.1.tgz", - "integrity": "sha512-v6PbKMGl/hWHGPxB2uGHsA66vusrXF66J/h1QiFXtU6z5zVSK8jq5xl95M1p3QNXmuEJKNP3nxoXfbgQNs7hJg==", + "version": "13.7.3", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.3.tgz", + "integrity": "sha512-ACCwbfeC6HjY2pnDii+Zer+MZ6sdOtwvLmDXRK/BoD3WNR551V22R6KEagwHoTRJ0ZlIhpCBkptpCU6+Ri/05w==", "dev": true, "requires": { "consolidate": "^0.14.0", @@ -12972,6 +10878,33 @@ "vue-template-es2015-compiler": "^1.6.0" }, "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0", + "postcss-load-options": "^1.2.0", + "postcss-load-plugins": "^2.3.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -12981,9 +10914,9 @@ } }, "vue-resource": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vue-resource/-/vue-resource-1.5.0.tgz", - "integrity": "sha512-em+Ihe+duUWQv4uKO8aFTGK+e/lvNtk5EBEmWaBYcfQzBmHhKR4jJAeVIHcG6otugmsme/DmYrOEPfbss+2XfQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/vue-resource/-/vue-resource-1.5.1.tgz", + "integrity": "sha512-o6V4wNgeqP+9v9b2bPXrr20CGNQPEXjpbUWdZWq9GJhqVeAGcYoeTtn/D4q059ZiyN0DIrDv/ADrQUmlUQcsmg==", "requires": { "got": "^8.0.3" } @@ -12991,7 +10924,7 @@ "vue-style-loader": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-3.1.2.tgz", - "integrity": "sha1-a2atNJmPyVIMLx5NX6QJFkHBWXo=", + "integrity": "sha512-ICtVdK/p+qXWpdSs2alWtsXt9YnDoYjQe0w5616j9+/EhjoxZkbun34uWgsMFnC1MhrMMwaWiImz3K2jK1Yp2Q==", "dev": true, "requires": { "hash-sum": "^1.0.2", @@ -13001,7 +10934,7 @@ "vue-template-compiler": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.4.4.tgz", - "integrity": "sha1-LN47cEEkmFwn1QtTh8lpG6UV+1c=", + "integrity": "sha512-XdHsNi8Z5WqwuFl/Z5eLKgE2DOEEOdMk1aA459uSgvwyy+pjKLBlQWsUpAtoR6o6Wmpujw6NtinAUGuqSTituQ==", "dev": true, "requires": { "de-indent": "^1.0.2", @@ -13009,27 +10942,18 @@ } }, "vue-template-es2015-compiler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz", - "integrity": "sha1-3EJpcTMwLOMBdSQ1amxht7abShg=", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, - "ware": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", - "integrity": "sha1-0bFPOdLiy0q4xAmPdW/ksWTkc9Q=", - "dev": true, - "requires": { - "wrap-fn": "^0.1.0" - } - }, "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha1-S8EsLr6KonenHx0/FNaFx7RGzQA=", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", + "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==", "dev": true, "requires": { - "chokidar": "^2.0.2", + "chokidar": "^2.1.8", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" } @@ -13037,16 +10961,16 @@ "wbuf": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, "requires": { "minimalistic-assert": "^1.0.0" } }, "webpack": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.11.0.tgz", - "integrity": "sha512-3kOFejWqj5ISpJk4Qj/V7w98h9Vl52wak3CLiw/cDOfbVTq7FeoZ0SdoHHY9PYlHr50ZS42OfvzE2vB4nncKQg==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", + "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==", "dev": true, "requires": { "acorn": "^5.0.0", @@ -13073,17 +10997,11 @@ "yargs": "^8.0.2" }, "dependencies": { - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true }, "has-flag": { "version": "2.0.0", @@ -13091,6 +11009,12 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -13122,7 +11046,7 @@ "webpack-dev-middleware": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz", - "integrity": "sha1-+PwRIM47T8VoDO7LQ9d3lmshEF4=", + "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", "dev": true, "requires": { "memory-fs": "~0.4.1", @@ -13130,33 +11054,25 @@ "path-is-absolute": "^1.0.0", "range-parser": "^1.0.3", "time-stamp": "^2.0.0" - }, - "dependencies": { - "time-stamp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", - "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=", - "dev": true - } } }, "webpack-dev-server": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.2.tgz", - "integrity": "sha1-H09MeL8YlTePN2gVkQgS2veaIW8=", + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz", + "integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==", "dev": true, "requires": { "ansi-html": "0.0.7", "array-includes": "^3.0.3", "bonjour": "^3.5.0", - "chokidar": "^2.0.0", - "compression": "^1.5.2", + "chokidar": "^2.1.2", + "compression": "^1.7.3", "connect-history-api-fallback": "^1.3.0", "debug": "^3.1.0", "del": "^3.0.0", "express": "^4.16.2", "html-entities": "^1.2.0", - "http-proxy-middleware": "~0.17.4", + "http-proxy-middleware": "^0.19.1", "import-local": "^1.0.0", "internal-ip": "1.2.0", "ip": "^1.1.5", @@ -13165,10 +11081,10 @@ "opn": "^5.1.0", "portfinder": "^1.0.9", "selfsigned": "^1.9.1", - "serve-index": "^1.7.2", + "serve-index": "^1.9.1", "sockjs": "0.3.19", - "sockjs-client": "1.1.4", - "spdy": "^3.4.1", + "sockjs-client": "1.1.5", + "spdy": "^4.0.0", "strip-ansi": "^3.0.0", "supports-color": "^5.1.0", "webpack-dev-middleware": "1.12.2", @@ -13202,9 +11118,9 @@ } }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -13243,18 +11159,18 @@ } }, "webpack-merge": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.2.tgz", - "integrity": "sha512-/0QYwW/H1N/CdXYA2PNPVbsxO3u2Fpz34vs72xm03SRfg6bMNGfMJIQEpQjKRvkG2JvT6oRJFpDtSrwbX8Jzvw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", "dev": true, "requires": { - "lodash": "^4.17.5" + "lodash": "^4.17.15" } }, "webpack-notifier": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.6.0.tgz", - "integrity": "sha1-/6yOVf+MRpdSuMG7sBGhbxCYbgI=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.8.0.tgz", + "integrity": "sha512-I6t76NoPe5DZCCm5geELmDV2wlJ89LbU425uN6T2FG8Ywrrt1ZcUMz6g8yWGNg4pttqTPFQJYUPjWAlzUEQ+cQ==", "dev": true, "requires": { "node-notifier": "^5.1.2", @@ -13263,9 +11179,9 @@ } }, "webpack-sources": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", - "integrity": "sha1-oQHrrlnWUHNU1x2AE5UKOot6WlQ=", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { "source-list-map": "^2.0.0", @@ -13275,25 +11191,26 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "websocket-driver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", "dev": true, "requires": { - "http-parser-js": ">=0.4.0", + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha1-XS/yKXcAPsaHpLhwc9+7rBRszyk=", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", "dev": true }, "whet.extend": { @@ -13303,9 +11220,9 @@ "dev": true }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -13318,34 +11235,12 @@ "dev": true }, "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "requires": { - "string-width": "^1.0.2" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } + "string-width": "^1.0.2 || 2" } }, "window-size": { @@ -13354,6 +11249,11 @@ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true }, + "wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==" + }, "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", @@ -13361,9 +11261,9 @@ "dev": true }, "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha1-rsxAWXb6talVJhgIRvDboojzpKA=", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "requires": { "errno": "~0.1.7" @@ -13401,34 +11301,30 @@ } } }, - "wrap-fn": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz", - "integrity": "sha1-8htuQQFv9KfjFyDbxjoJAWvfmEU=", - "dev": true, - "requires": { - "co": "3.1.0" - }, - "dependencies": { - "co": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", - "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=", - "dev": true - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xlsx": { + "version": "0.15.6", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.15.6.tgz", + "integrity": "sha512-7vD9eutyLs65iDjNFimVN+gk/oDkfkCgpQUjdE82QgzJCrBHC4bGPH7fzKVyy0UPp3gyFVQTQEFJaWaAvZCShQ==", + "requires": { + "adler-32": "~1.2.0", + "cfb": "^1.1.4", + "codepage": "~1.14.0", + "commander": "~2.17.1", + "crc-32": "~1.2.0", + "exit-on-epipe": "~1.0.1", + "ssf": "~0.10.3", + "wmf": "~1.0.1" + } }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "3.2.1", @@ -13484,7 +11380,7 @@ "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { "execa": "^0.7.0", @@ -13501,12 +11397,6 @@ "pify": "^2.0.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -13567,16 +11457,6 @@ "dev": true } } - }, - "yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.0.1" - } } } } diff --git a/package.json b/package.json index f0e275e89a..5546037ba6 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,10 @@ "watch-poll": "npm run watch -- --watch-poll", "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", - "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js " + "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" + }, + "engines": { + "node": ">=0.12" }, "devDependencies": { "axios": ">=0.18.1", @@ -21,14 +24,21 @@ "vue-template-compiler": "2.4.4" }, "dependencies": { - "blueimp-file-upload": "^9.18.0", - "bootstrap": "^3.3.7", - "bootstrap-colorpicker": "^2.5.1", - "bootstrap-datepicker": "^1.6.4", + "@fortawesome/fontawesome-free": "^5.12.0", + "admin-lte": "^2.4.18", + "ajv": "^6.10.2", + "blueimp-file-upload": "^9.34.0", + "bootstrap": "^3.4.1", + "bootstrap-colorpicker": "^2.5.3", + "bootstrap-datepicker": "^1.9.0", "bootstrap-less": "^3.3.8", + "bootstrap-table": "^1.15.5", + "chart.js": "^2.9.3", "ekko-lightbox": "^5.1.1", "font-awesome": "^4.7.0", "icheck": "^1.0.2", + "imagemin": "^5.3.1", + "jquery-form-validator": "^2.3.79", "jquery-slimscroll": "^1.3.8", "jquery-ui": "^1.12.1", "jquery-ui-bundle": "^1.12.1", @@ -38,6 +48,7 @@ "list.js": "^1.5.0", "papaparse": "^4.3.3", "select2": "4.0.13", + "tableexport.jquery.plugin": "^1.10.12", "tether": "^1.4.0", "vue-resource": "^1.3.3" } diff --git a/phpmd.xml b/phpmd.xml new file mode 100644 index 0000000000..d991b90fbb --- /dev/null +++ b/phpmd.xml @@ -0,0 +1,54 @@ + + + + Inspired by https://github.com/phpmd/phpmd/issues/137 + using http://phpmd.org/documentation/creating-a-ruleset.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + \ No newline at end of file diff --git a/public/_debugbar/assets/jquery.min.map b/public/_debugbar/assets/jquery.min.map deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/public/assets/css/themes/dark-green.css b/public/assets/css/themes/dark-green.css deleted file mode 100644 index f64c178c54..0000000000 --- a/public/assets/css/themes/dark-green.css +++ /dev/null @@ -1,145 +0,0 @@ -:root { - --background: #222; - --back-main: #333; - --back-sub: #444; - --header: #18A452; /* Use same as Header picker */ - --text-main: #FFF; - --text-sub: #BBB; -} - -a, a:link, a:visited, .btn-primary.hover { - color: var(--header); -} -#accessoriesTable>tbody>tr>td>nobr>a>i.fa { - color: var(--text-main); -} -#assetsListingTable>tbody>tr>td>nobr>a>i.fa { - color: var(--text-main); -} -#assetsListingTable>tbody>tr.selected>td { - background-color: var(--back-main); -} -.box, .box.box-default { - border-top: 3px solid var(--header); - border-top-color: var(--header); -} -.box-body, .box-footer, .box-header { - background-color: var(--back-sub); - color: var(--text-main); -} -.btn-default{ - background-color: var(--back-main); - color: var(--header); -} -.btn-default:active, .btn-default:focus, .btn-default:hover { - background-color: var(--back-sub); - color: var(--header); -} -.btn-primary, .btn-primary.hover, .btn-primary:active, .btn-primary:hover, .text-green { - color: var(--text-main)!important; -} -#componentsTable>tbody>tr>td>nobr>a>i.fa { - color: var(--text-main); -} -#consumablesTable>tbody>tr>td>nobr>a>i.fa { - color: var(--text-main); -} -.content-wrapper { - background-color: var(--background); -} -#create-form>div>div>div>span.input-group-addon { - background-color: var(--back-sub); - color: var(--text-main); -} -#create-form>div>div>div>span>i.fa { - background-color: var(--back-sub); - color: var(--header); -} -#details>div>div>div>table { - background-color: transparent; -} -.dropdown-menu, .dropdown-menu>li>a { - background-color: var(--back-sub); - color: var(--header); -} -.dropdown-menu>li>a:hover { - background-color: var(--back-main); - color: var(--text-main); -} -.form-control { - background-color: var(--back-main); - color: var(--text-main); -} -h1 { - color: var(--text-main); -} -.help-block { - color: var(--text-sub); -} -input[type=text], input[type=search] { - background-color: var(--back-sub); - color: var(--text-main); -} -#licensesTable>tbody>tr>td>nobr>a>i.fa { - color: var(--text-main); -} -.main-footer { - background-color: var(--back-main); - color: var(--text-main); -} -.nav-tabs-custom>.nav-tabs>li>a, .nav-tabs-custom>.nav-tabs>li.active>a { - color: var(--text-main); -} -.nav-tabs-custom>.nav-tabs>li.active { - border-top-color: var(--header); -} -.nav-tabs-custom>.nav-tabs>li.active>a { - background-color: var(--back-main); -} -.nav-tabs-custom>.nav-tabs>li.active>a:hover { - background-color: var(--back-sub); - color: var(--text-main); -} -.nav-tabs-custom, .nav-tabs-custom>.tab-content { - background-color: var(--back-main); -} -.navbar-nav>.tasks-menu>.dropdown-menu>li.header { - background-color: var(--back-main); - color: var(--header); -} -.open>.dropdown-toggle.btn-default { - background-color: var(--back-sub); - color: var(--header); -} -.panel { - background-color: var(--back-sub); - color: var(--text-main); -} -.panel-default>.panel-heading { - background-color: var(--back-main); - color: var(--header); -} -.select2-selection--single { - background-color: var(--back-sub)!important; - color: var(--text-main)!important; -} -.select2-container--default .select2-selection--single .select2-selection__rendered { - color: var(--text-main); -} -.select2-dropdown { - background-color: var(--back-main); - color: var(--text-main); -} -.skin-green .main-header .navbar .dropdown-menu li a { - color: var(--header); -} -.skin-green .sidebar-menu>li.active>a, .skin-green .sidebar-menu>li:hover>a, .sidebar-toggle:hover { - background-color: var(--header)!important; -} -.tab-content, .tab-pane { - background-color: var(--back-main); - color: var(--text-main); -} -.table-striped>tbody>tr:nth-of-type(odd) { - background-color: var(--back-sub); -} diff --git a/public/css/AdminLTE.css b/public/css/AdminLTE.css deleted file mode 100755 index 7a902886b5..0000000000 Binary files a/public/css/AdminLTE.css and /dev/null differ diff --git a/public/css/AdminLTE.css.map b/public/css/AdminLTE.css.map deleted file mode 100644 index 7d26bfc9b0..0000000000 Binary files a/public/css/AdminLTE.css.map and /dev/null differ diff --git a/public/css/AdminLTE.min.css b/public/css/AdminLTE.min.css deleted file mode 100755 index 396657a381..0000000000 Binary files a/public/css/AdminLTE.min.css and /dev/null differ diff --git a/public/css/all.47a3626f2a026645fe48f025aacc900f.css b/public/css/all.47a3626f2a026645fe48f025aacc900f.css deleted file mode 100644 index be3881e615..0000000000 Binary files a/public/css/all.47a3626f2a026645fe48f025aacc900f.css and /dev/null differ diff --git a/public/css/all.62471b1dabf4426689e067404cda00a2.css b/public/css/all.62471b1dabf4426689e067404cda00a2.css deleted file mode 100644 index 20547187db..0000000000 Binary files a/public/css/all.62471b1dabf4426689e067404cda00a2.css and /dev/null differ diff --git a/public/css/all.c320a5e511c1340ea16bc7facdbdb57b.css b/public/css/all.c320a5e511c1340ea16bc7facdbdb57b.css deleted file mode 100644 index 88519a3d43..0000000000 Binary files a/public/css/all.c320a5e511c1340ea16bc7facdbdb57b.css and /dev/null differ diff --git a/public/css/all.css b/public/css/all.css deleted file mode 100644 index 88519a3d43..0000000000 Binary files a/public/css/all.css and /dev/null differ diff --git a/public/css/app.47a3626f2a026645fe48f025aacc900f.css b/public/css/app.47a3626f2a026645fe48f025aacc900f.css deleted file mode 100644 index be3881e615..0000000000 Binary files a/public/css/app.47a3626f2a026645fe48f025aacc900f.css and /dev/null differ diff --git a/public/css/app.62471b1dabf4426689e067404cda00a2.css b/public/css/app.62471b1dabf4426689e067404cda00a2.css deleted file mode 100644 index 20547187db..0000000000 Binary files a/public/css/app.62471b1dabf4426689e067404cda00a2.css and /dev/null differ diff --git a/public/css/app.css b/public/css/app.css deleted file mode 100644 index 89a60fedb2..0000000000 Binary files a/public/css/app.css and /dev/null differ diff --git a/public/css/app.css.map b/public/css/app.css.map deleted file mode 100644 index 051d67395d..0000000000 Binary files a/public/css/app.css.map and /dev/null differ diff --git a/public/js/plugins/iCheck/minimal/blue.png b/public/css/blue.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/blue.png rename to public/css/blue.png diff --git a/public/js/plugins/iCheck/minimal/blue@2x.png b/public/css/blue@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/blue@2x.png rename to public/css/blue@2x.png diff --git a/public/css/build/AdminLTE.css b/public/css/build/AdminLTE.css new file mode 100644 index 0000000000..9aeb043740 Binary files /dev/null and b/public/css/build/AdminLTE.css differ diff --git a/public/css/build/AdminLTE.css.map b/public/css/build/AdminLTE.css.map new file mode 100644 index 0000000000..8d6c361dd7 Binary files /dev/null and b/public/css/build/AdminLTE.css.map differ diff --git a/public/css/build/app.css b/public/css/build/app.css new file mode 100644 index 0000000000..a190092b6c Binary files /dev/null and b/public/css/build/app.css differ diff --git a/public/css/build/app.css.map b/public/css/build/app.css.map new file mode 100644 index 0000000000..2522e80582 Binary files /dev/null and b/public/css/build/app.css.map differ diff --git a/public/css/build/bootstrap.css b/public/css/build/bootstrap.css new file mode 100644 index 0000000000..d654e48159 Binary files /dev/null and b/public/css/build/bootstrap.css differ diff --git a/public/css/build/overrides.css b/public/css/build/overrides.css new file mode 100644 index 0000000000..0e38d4e70c Binary files /dev/null and b/public/css/build/overrides.css differ diff --git a/public/css/build/signature-pad.min.css b/public/css/build/signature-pad.min.css new file mode 100644 index 0000000000..8b13789179 Binary files /dev/null and b/public/css/build/signature-pad.min.css differ diff --git a/resources/assets/js/plugins/iCheck/minimal/_all.css b/public/css/dist/_all.css old mode 100755 new mode 100644 similarity index 82% rename from resources/assets/js/plugins/iCheck/minimal/_all.css rename to public/css/dist/_all.css index b2165ecc35..8cf8aca9bd Binary files a/resources/assets/js/plugins/iCheck/minimal/_all.css and b/public/css/dist/_all.css differ diff --git a/public/js/plugins/iCheck/minimal/aero.css b/public/css/dist/aero.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/aero.css rename to public/css/dist/aero.css index c97acc8c11..0a7a945382 Binary files a/public/js/plugins/iCheck/minimal/aero.css and b/public/css/dist/aero.css differ diff --git a/public/js/plugins/iCheck/minimal/aero.png b/public/css/dist/aero.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/aero.png rename to public/css/dist/aero.png diff --git a/public/js/plugins/iCheck/minimal/aero@2x.png b/public/css/dist/aero@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/aero@2x.png rename to public/css/dist/aero@2x.png diff --git a/public/css/dist/all.css b/public/css/dist/all.css index a1f66bd869..e30e7efe33 100644 Binary files a/public/css/dist/all.css and b/public/css/dist/all.css differ diff --git a/public/js/plugins/iCheck/minimal/blue.css b/public/css/dist/blue.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/blue.css rename to public/css/dist/blue.css index 42477cd660..c290097518 Binary files a/public/js/plugins/iCheck/minimal/blue.css and b/public/css/dist/blue.css differ diff --git a/resources/assets/js/plugins/iCheck/minimal/blue.png b/public/css/dist/blue.png old mode 100755 new mode 100644 similarity index 100% rename from resources/assets/js/plugins/iCheck/minimal/blue.png rename to public/css/dist/blue.png diff --git a/resources/assets/js/plugins/iCheck/minimal/blue@2x.png b/public/css/dist/blue@2x.png old mode 100755 new mode 100644 similarity index 100% rename from resources/assets/js/plugins/iCheck/minimal/blue@2x.png rename to public/css/dist/blue@2x.png diff --git a/public/css/dist/bootstrap-table.css b/public/css/dist/bootstrap-table.css new file mode 100644 index 0000000000..2c4a67341a Binary files /dev/null and b/public/css/dist/bootstrap-table.css differ diff --git a/public/js/plugins/iCheck/minimal/green.css b/public/css/dist/green.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/green.css rename to public/css/dist/green.css index bd1e3d0feb..aa685f3665 Binary files a/public/js/plugins/iCheck/minimal/green.css and b/public/css/dist/green.css differ diff --git a/public/js/plugins/iCheck/minimal/green.png b/public/css/dist/green.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/green.png rename to public/css/dist/green.png diff --git a/public/js/plugins/iCheck/minimal/green@2x.png b/public/css/dist/green@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/green@2x.png rename to public/css/dist/green@2x.png diff --git a/public/js/plugins/iCheck/minimal/grey.css b/public/css/dist/grey.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/grey.css rename to public/css/dist/grey.css index 6e2730c662..f242697737 Binary files a/public/js/plugins/iCheck/minimal/grey.css and b/public/css/dist/grey.css differ diff --git a/public/js/plugins/iCheck/minimal/grey.png b/public/css/dist/grey.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/grey.png rename to public/css/dist/grey.png diff --git a/public/js/plugins/iCheck/minimal/grey@2x.png b/public/css/dist/grey@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/grey@2x.png rename to public/css/dist/grey@2x.png diff --git a/resources/assets/js/plugins/iCheck/minimal/minimal.css b/public/css/dist/minimal.css old mode 100755 new mode 100644 similarity index 83% rename from resources/assets/js/plugins/iCheck/minimal/minimal.css rename to public/css/dist/minimal.css index 7c0e52e1da..c2c6620fc0 Binary files a/resources/assets/js/plugins/iCheck/minimal/minimal.css and b/public/css/dist/minimal.css differ diff --git a/public/js/plugins/iCheck/minimal/minimal.png b/public/css/dist/minimal.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/minimal.png rename to public/css/dist/minimal.png diff --git a/public/js/plugins/iCheck/minimal/minimal@2x.png b/public/css/dist/minimal@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/minimal@2x.png rename to public/css/dist/minimal@2x.png diff --git a/public/js/plugins/iCheck/minimal/orange.css b/public/css/dist/orange.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/orange.css rename to public/css/dist/orange.css index 842e400a9d..ba1b9c34a3 Binary files a/public/js/plugins/iCheck/minimal/orange.css and b/public/css/dist/orange.css differ diff --git a/public/js/plugins/iCheck/minimal/orange.png b/public/css/dist/orange.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/orange.png rename to public/css/dist/orange.png diff --git a/public/js/plugins/iCheck/minimal/orange@2x.png b/public/css/dist/orange@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/orange@2x.png rename to public/css/dist/orange@2x.png diff --git a/public/js/plugins/iCheck/minimal/pink.css b/public/css/dist/pink.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/pink.css rename to public/css/dist/pink.css index 10ace2188f..77c5741862 Binary files a/public/js/plugins/iCheck/minimal/pink.css and b/public/css/dist/pink.css differ diff --git a/public/js/plugins/iCheck/minimal/pink.png b/public/css/dist/pink.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/pink.png rename to public/css/dist/pink.png diff --git a/public/js/plugins/iCheck/minimal/pink@2x.png b/public/css/dist/pink@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/pink@2x.png rename to public/css/dist/pink@2x.png diff --git a/public/js/plugins/iCheck/minimal/purple.css b/public/css/dist/purple.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/purple.css rename to public/css/dist/purple.css index 1c5dcbc716..d509f04346 Binary files a/public/js/plugins/iCheck/minimal/purple.css and b/public/css/dist/purple.css differ diff --git a/public/js/plugins/iCheck/minimal/purple.png b/public/css/dist/purple.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/purple.png rename to public/css/dist/purple.png diff --git a/public/js/plugins/iCheck/minimal/purple@2x.png b/public/css/dist/purple@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/purple@2x.png rename to public/css/dist/purple@2x.png diff --git a/public/js/plugins/iCheck/minimal/red.css b/public/css/dist/red.css old mode 100755 new mode 100644 similarity index 84% rename from public/js/plugins/iCheck/minimal/red.css rename to public/css/dist/red.css index 9340c4f6f6..2280e5b0db Binary files a/public/js/plugins/iCheck/minimal/red.css and b/public/css/dist/red.css differ diff --git a/public/js/plugins/iCheck/minimal/red.png b/public/css/dist/red.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/red.png rename to public/css/dist/red.png diff --git a/public/js/plugins/iCheck/minimal/red@2x.png b/public/css/dist/red@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/red@2x.png rename to public/css/dist/red@2x.png diff --git a/public/css/dist/signature-pad.css b/public/css/dist/signature-pad.css new file mode 100755 index 0000000000..218b9c2365 Binary files /dev/null and b/public/css/dist/signature-pad.css differ diff --git a/public/css/dist/skins/skin-black-dark.css b/public/css/dist/skins/skin-black-dark.css new file mode 100644 index 0000000000..cd4369222e Binary files /dev/null and b/public/css/dist/skins/skin-black-dark.css differ diff --git a/public/css/dist/skins/skin-black-dark.css.map b/public/css/dist/skins/skin-black-dark.css.map new file mode 100644 index 0000000000..6f36635a2b Binary files /dev/null and b/public/css/dist/skins/skin-black-dark.css.map differ diff --git a/public/css/dist/skins/skin-black-dark.min.css b/public/css/dist/skins/skin-black-dark.min.css new file mode 100644 index 0000000000..8468fc80af Binary files /dev/null and b/public/css/dist/skins/skin-black-dark.min.css differ diff --git a/public/css/dist/skins/skin-black.css b/public/css/dist/skins/skin-black.css new file mode 100644 index 0000000000..ff91e26834 Binary files /dev/null and b/public/css/dist/skins/skin-black.css differ diff --git a/public/css/skins/skin-purple-light.css.map b/public/css/dist/skins/skin-black.css.map similarity index 83% rename from public/css/skins/skin-purple-light.css.map rename to public/css/dist/skins/skin-black.css.map index eb1ef604ef..bb62df3bf9 100644 Binary files a/public/css/skins/skin-purple-light.css.map and b/public/css/dist/skins/skin-black.css.map differ diff --git a/public/css/dist/skins/skin-blue-dark.css b/public/css/dist/skins/skin-blue-dark.css new file mode 100644 index 0000000000..9f8a9dc9ba Binary files /dev/null and b/public/css/dist/skins/skin-blue-dark.css differ diff --git a/public/css/dist/skins/skin-blue-dark.min.css b/public/css/dist/skins/skin-blue-dark.min.css new file mode 100644 index 0000000000..3fdee5a6ef Binary files /dev/null and b/public/css/dist/skins/skin-blue-dark.min.css differ diff --git a/public/css/dist/skins/skin-blue.css b/public/css/dist/skins/skin-blue.css new file mode 100644 index 0000000000..9bc7aaa237 Binary files /dev/null and b/public/css/dist/skins/skin-blue.css differ diff --git a/public/css/dist/skins/skin-blue.css.map b/public/css/dist/skins/skin-blue.css.map new file mode 100644 index 0000000000..ae04f3e7b5 Binary files /dev/null and b/public/css/dist/skins/skin-blue.css.map differ diff --git a/public/css/dist/skins/skin-contrast.css b/public/css/dist/skins/skin-contrast.css new file mode 100644 index 0000000000..cee4a18de9 Binary files /dev/null and b/public/css/dist/skins/skin-contrast.css differ diff --git a/public/css/dist/skins/skin-contrast.css.map b/public/css/dist/skins/skin-contrast.css.map new file mode 100644 index 0000000000..38f07b4787 Binary files /dev/null and b/public/css/dist/skins/skin-contrast.css.map differ diff --git a/public/css/dist/skins/skin-contrast.min.css b/public/css/dist/skins/skin-contrast.min.css new file mode 100644 index 0000000000..4371050957 Binary files /dev/null and b/public/css/dist/skins/skin-contrast.min.css differ diff --git a/public/css/dist/skins/skin-green-dark.css b/public/css/dist/skins/skin-green-dark.css new file mode 100644 index 0000000000..d993b76e01 Binary files /dev/null and b/public/css/dist/skins/skin-green-dark.css differ diff --git a/public/css/dist/skins/skin-green-dark.css.map b/public/css/dist/skins/skin-green-dark.css.map new file mode 100644 index 0000000000..947c4d4953 Binary files /dev/null and b/public/css/dist/skins/skin-green-dark.css.map differ diff --git a/public/css/dist/skins/skin-green-dark.min.css b/public/css/dist/skins/skin-green-dark.min.css new file mode 100644 index 0000000000..29ec24b7fd Binary files /dev/null and b/public/css/dist/skins/skin-green-dark.min.css differ diff --git a/public/css/dist/skins/skin-green.css b/public/css/dist/skins/skin-green.css new file mode 100644 index 0000000000..94fdc44ec8 Binary files /dev/null and b/public/css/dist/skins/skin-green.css differ diff --git a/public/css/dist/skins/skin-green.css.map b/public/css/dist/skins/skin-green.css.map new file mode 100644 index 0000000000..0be586716c Binary files /dev/null and b/public/css/dist/skins/skin-green.css.map differ diff --git a/public/css/dist/skins/skin-orange-dark.css b/public/css/dist/skins/skin-orange-dark.css new file mode 100644 index 0000000000..4c5e89bcf3 Binary files /dev/null and b/public/css/dist/skins/skin-orange-dark.css differ diff --git a/public/css/dist/skins/skin-orange-dark.css.map b/public/css/dist/skins/skin-orange-dark.css.map new file mode 100644 index 0000000000..71528e6df6 Binary files /dev/null and b/public/css/dist/skins/skin-orange-dark.css.map differ diff --git a/public/css/dist/skins/skin-orange-dark.min.css b/public/css/dist/skins/skin-orange-dark.min.css new file mode 100644 index 0000000000..71e29f8a00 Binary files /dev/null and b/public/css/dist/skins/skin-orange-dark.min.css differ diff --git a/public/css/dist/skins/skin-orange.css b/public/css/dist/skins/skin-orange.css new file mode 100644 index 0000000000..77b8e9b0c9 Binary files /dev/null and b/public/css/dist/skins/skin-orange.css differ diff --git a/public/css/dist/skins/skin-orange.css.map b/public/css/dist/skins/skin-orange.css.map new file mode 100644 index 0000000000..527c0752a6 Binary files /dev/null and b/public/css/dist/skins/skin-orange.css.map differ diff --git a/public/css/dist/skins/skin-purple-dark.css b/public/css/dist/skins/skin-purple-dark.css new file mode 100644 index 0000000000..5d31137b9e Binary files /dev/null and b/public/css/dist/skins/skin-purple-dark.css differ diff --git a/public/css/dist/skins/skin-purple-dark.css.map b/public/css/dist/skins/skin-purple-dark.css.map new file mode 100644 index 0000000000..d5df2bcdf6 Binary files /dev/null and b/public/css/dist/skins/skin-purple-dark.css.map differ diff --git a/public/css/dist/skins/skin-purple-dark.min.css b/public/css/dist/skins/skin-purple-dark.min.css new file mode 100644 index 0000000000..70a10d3a58 Binary files /dev/null and b/public/css/dist/skins/skin-purple-dark.min.css differ diff --git a/public/css/dist/skins/skin-purple.css b/public/css/dist/skins/skin-purple.css new file mode 100644 index 0000000000..3a50660659 Binary files /dev/null and b/public/css/dist/skins/skin-purple.css differ diff --git a/public/css/dist/skins/skin-purple.css.map b/public/css/dist/skins/skin-purple.css.map new file mode 100644 index 0000000000..e71222c039 Binary files /dev/null and b/public/css/dist/skins/skin-purple.css.map differ diff --git a/public/css/dist/skins/skin-red-dark.css b/public/css/dist/skins/skin-red-dark.css new file mode 100644 index 0000000000..a268a76dc0 Binary files /dev/null and b/public/css/dist/skins/skin-red-dark.css differ diff --git a/public/css/dist/skins/skin-red-dark.css.map b/public/css/dist/skins/skin-red-dark.css.map new file mode 100644 index 0000000000..9aa2a2fb9a Binary files /dev/null and b/public/css/dist/skins/skin-red-dark.css.map differ diff --git a/public/css/dist/skins/skin-red-dark.min.css b/public/css/dist/skins/skin-red-dark.min.css new file mode 100644 index 0000000000..cf07179944 Binary files /dev/null and b/public/css/dist/skins/skin-red-dark.min.css differ diff --git a/public/css/dist/skins/skin-red.css b/public/css/dist/skins/skin-red.css new file mode 100644 index 0000000000..099836d4f2 Binary files /dev/null and b/public/css/dist/skins/skin-red.css differ diff --git a/public/css/skins/skin-black-light.css.map b/public/css/dist/skins/skin-red.css.map similarity index 83% rename from public/css/skins/skin-black-light.css.map rename to public/css/dist/skins/skin-red.css.map index 0820408cc3..c407b1c169 100644 Binary files a/public/css/skins/skin-black-light.css.map and b/public/css/dist/skins/skin-red.css.map differ diff --git a/public/css/dist/skins/skin-yellow-dark.css b/public/css/dist/skins/skin-yellow-dark.css new file mode 100644 index 0000000000..968cfe69c7 Binary files /dev/null and b/public/css/dist/skins/skin-yellow-dark.css differ diff --git a/public/css/dist/skins/skin-yellow-dark.css.map b/public/css/dist/skins/skin-yellow-dark.css.map new file mode 100644 index 0000000000..72bc940c2c Binary files /dev/null and b/public/css/dist/skins/skin-yellow-dark.css.map differ diff --git a/public/css/dist/skins/skin-yellow-dark.min.css b/public/css/dist/skins/skin-yellow-dark.min.css new file mode 100644 index 0000000000..860a6dfd81 Binary files /dev/null and b/public/css/dist/skins/skin-yellow-dark.min.css differ diff --git a/public/css/dist/skins/skin-yellow.css b/public/css/dist/skins/skin-yellow.css new file mode 100644 index 0000000000..bae6c794a1 Binary files /dev/null and b/public/css/dist/skins/skin-yellow.css differ diff --git a/public/css/dist/skins/skin-yellow.css.map b/public/css/dist/skins/skin-yellow.css.map new file mode 100644 index 0000000000..0afce7f51d Binary files /dev/null and b/public/css/dist/skins/skin-yellow.css.map differ diff --git a/resources/assets/js/plugins/iCheck/minimal/yellow.css b/public/css/dist/yellow.css old mode 100755 new mode 100644 similarity index 84% rename from resources/assets/js/plugins/iCheck/minimal/yellow.css rename to public/css/dist/yellow.css index 2c38423130..730bb4c471 Binary files a/resources/assets/js/plugins/iCheck/minimal/yellow.css and b/public/css/dist/yellow.css differ diff --git a/public/js/plugins/iCheck/minimal/yellow.png b/public/css/dist/yellow.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/yellow.png rename to public/css/dist/yellow.png diff --git a/public/js/plugins/iCheck/minimal/yellow@2x.png b/public/css/dist/yellow@2x.png old mode 100755 new mode 100644 similarity index 100% rename from public/js/plugins/iCheck/minimal/yellow@2x.png rename to public/css/dist/yellow@2x.png diff --git a/public/css/ekko-lightbox.css b/public/css/ekko-lightbox.css deleted file mode 100755 index ec3432ff48..0000000000 Binary files a/public/css/ekko-lightbox.css and /dev/null differ diff --git a/public/css/ekko-lightbox.min.css b/public/css/ekko-lightbox.min.css deleted file mode 100755 index c81b9cc68a..0000000000 Binary files a/public/css/ekko-lightbox.min.css and /dev/null differ diff --git a/public/css/font-awesome/font-awesome.css b/public/css/font-awesome/font-awesome.css deleted file mode 100644 index ee906a8196..0000000000 Binary files a/public/css/font-awesome/font-awesome.css and /dev/null differ diff --git a/public/css/font-awesome/font-awesome.min.css b/public/css/font-awesome/font-awesome.min.css deleted file mode 100644 index 540440ce89..0000000000 Binary files a/public/css/font-awesome/font-awesome.min.css and /dev/null differ diff --git a/public/css/jquery.typeahead.min.css b/public/css/jquery.typeahead.min.css deleted file mode 100755 index 1c97a579e8..0000000000 Binary files a/public/css/jquery.typeahead.min.css and /dev/null differ diff --git a/public/css/lib/select2.css b/public/css/lib/select2.css deleted file mode 100755 index ae46ec3b42..0000000000 Binary files a/public/css/lib/select2.css and /dev/null differ diff --git a/public/css/metisMenu.css b/public/css/metisMenu.css deleted file mode 100755 index 76376c39ae..0000000000 Binary files a/public/css/metisMenu.css and /dev/null differ diff --git a/public/css/metisMenu.min.css b/public/css/metisMenu.min.css deleted file mode 100755 index a1d0ef3994..0000000000 Binary files a/public/css/metisMenu.min.css and /dev/null differ diff --git a/public/css/morris.css b/public/css/morris.css deleted file mode 100755 index 209f09156b..0000000000 Binary files a/public/css/morris.css and /dev/null differ diff --git a/public/css/select2x2.png b/public/css/select2x2.png deleted file mode 100755 index 4bdd5c961d..0000000000 Binary files a/public/css/select2x2.png and /dev/null differ diff --git a/public/css/skins/_all-skins.css b/public/css/skins/_all-skins.css deleted file mode 100755 index 9af6a45871..0000000000 Binary files a/public/css/skins/_all-skins.css and /dev/null differ diff --git a/public/css/skins/_all-skins.min.css b/public/css/skins/_all-skins.min.css deleted file mode 100755 index 1710db5cb2..0000000000 Binary files a/public/css/skins/_all-skins.min.css and /dev/null differ diff --git a/public/css/skins/dist/skin-black-dark.css b/public/css/skins/dist/skin-black-dark.css new file mode 100644 index 0000000000..357442c6dc Binary files /dev/null and b/public/css/skins/dist/skin-black-dark.css differ diff --git a/public/css/skins/dist/skin-black-dark.css.map b/public/css/skins/dist/skin-black-dark.css.map new file mode 100644 index 0000000000..ed263604ce Binary files /dev/null and b/public/css/skins/dist/skin-black-dark.css.map differ diff --git a/public/css/skins/dist/skin-black.css b/public/css/skins/dist/skin-black.css new file mode 100644 index 0000000000..320500647f Binary files /dev/null and b/public/css/skins/dist/skin-black.css differ diff --git a/public/css/skins/dist/skin-black.css.map b/public/css/skins/dist/skin-black.css.map new file mode 100644 index 0000000000..78de1d8c83 Binary files /dev/null and b/public/css/skins/dist/skin-black.css.map differ diff --git a/public/css/skins/dist/skin-blue-dark.css b/public/css/skins/dist/skin-blue-dark.css new file mode 100644 index 0000000000..9f8a9dc9ba Binary files /dev/null and b/public/css/skins/dist/skin-blue-dark.css differ diff --git a/public/css/skins/dist/skin-blue-dark.css.map b/public/css/skins/dist/skin-blue-dark.css.map new file mode 100644 index 0000000000..b1487168bf Binary files /dev/null and b/public/css/skins/dist/skin-blue-dark.css.map differ diff --git a/public/css/skins/dist/skin-blue.css b/public/css/skins/dist/skin-blue.css new file mode 100644 index 0000000000..c023dbbbfb Binary files /dev/null and b/public/css/skins/dist/skin-blue.css differ diff --git a/public/css/skins/dist/skin-blue.css.map b/public/css/skins/dist/skin-blue.css.map new file mode 100644 index 0000000000..e259dd1750 Binary files /dev/null and b/public/css/skins/dist/skin-blue.css.map differ diff --git a/public/css/skins/dist/skin-contrast.css b/public/css/skins/dist/skin-contrast.css new file mode 100644 index 0000000000..ac865a26a9 Binary files /dev/null and b/public/css/skins/dist/skin-contrast.css differ diff --git a/public/css/skins/dist/skin-contrast.css.map b/public/css/skins/dist/skin-contrast.css.map new file mode 100644 index 0000000000..21f072ae12 Binary files /dev/null and b/public/css/skins/dist/skin-contrast.css.map differ diff --git a/public/css/skins/dist/skin-green-dark.css b/public/css/skins/dist/skin-green-dark.css new file mode 100644 index 0000000000..cf08fa534f Binary files /dev/null and b/public/css/skins/dist/skin-green-dark.css differ diff --git a/public/css/skins/dist/skin-green-dark.css.map b/public/css/skins/dist/skin-green-dark.css.map new file mode 100644 index 0000000000..3b7f463971 Binary files /dev/null and b/public/css/skins/dist/skin-green-dark.css.map differ diff --git a/public/css/skins/dist/skin-green.css b/public/css/skins/dist/skin-green.css new file mode 100644 index 0000000000..713e7ada12 Binary files /dev/null and b/public/css/skins/dist/skin-green.css differ diff --git a/public/css/skins/dist/skin-green.css.map b/public/css/skins/dist/skin-green.css.map new file mode 100644 index 0000000000..f15b36185f Binary files /dev/null and b/public/css/skins/dist/skin-green.css.map differ diff --git a/public/css/skins/dist/skin-orange-dark.css b/public/css/skins/dist/skin-orange-dark.css new file mode 100644 index 0000000000..1c165c1293 Binary files /dev/null and b/public/css/skins/dist/skin-orange-dark.css differ diff --git a/public/css/skins/dist/skin-orange-dark.css.map b/public/css/skins/dist/skin-orange-dark.css.map new file mode 100644 index 0000000000..146dff6dec Binary files /dev/null and b/public/css/skins/dist/skin-orange-dark.css.map differ diff --git a/public/css/skins/dist/skin-orange.css b/public/css/skins/dist/skin-orange.css new file mode 100644 index 0000000000..7f5f69e8b3 Binary files /dev/null and b/public/css/skins/dist/skin-orange.css differ diff --git a/public/css/skins/dist/skin-orange.css.map b/public/css/skins/dist/skin-orange.css.map new file mode 100644 index 0000000000..d11cf2d701 Binary files /dev/null and b/public/css/skins/dist/skin-orange.css.map differ diff --git a/public/css/skins/dist/skin-purple-dark.css b/public/css/skins/dist/skin-purple-dark.css new file mode 100644 index 0000000000..86c12b1339 Binary files /dev/null and b/public/css/skins/dist/skin-purple-dark.css differ diff --git a/public/css/skins/dist/skin-purple-dark.css.map b/public/css/skins/dist/skin-purple-dark.css.map new file mode 100644 index 0000000000..18021535d3 Binary files /dev/null and b/public/css/skins/dist/skin-purple-dark.css.map differ diff --git a/public/css/skins/dist/skin-purple.css b/public/css/skins/dist/skin-purple.css new file mode 100644 index 0000000000..dce5507013 Binary files /dev/null and b/public/css/skins/dist/skin-purple.css differ diff --git a/public/css/skins/dist/skin-purple.css.map b/public/css/skins/dist/skin-purple.css.map new file mode 100644 index 0000000000..b56f73c57c Binary files /dev/null and b/public/css/skins/dist/skin-purple.css.map differ diff --git a/public/css/skins/dist/skin-red-dark.css b/public/css/skins/dist/skin-red-dark.css new file mode 100644 index 0000000000..5c64e60b45 Binary files /dev/null and b/public/css/skins/dist/skin-red-dark.css differ diff --git a/public/css/skins/dist/skin-red-dark.css.map b/public/css/skins/dist/skin-red-dark.css.map new file mode 100644 index 0000000000..d6d49dbb7a Binary files /dev/null and b/public/css/skins/dist/skin-red-dark.css.map differ diff --git a/public/css/skins/dist/skin-red.css b/public/css/skins/dist/skin-red.css new file mode 100644 index 0000000000..0670a5689f Binary files /dev/null and b/public/css/skins/dist/skin-red.css differ diff --git a/public/css/skins/dist/skin-red.css.map b/public/css/skins/dist/skin-red.css.map new file mode 100644 index 0000000000..c4f70c1f39 Binary files /dev/null and b/public/css/skins/dist/skin-red.css.map differ diff --git a/public/css/skins/dist/skin-yellow-dark.css b/public/css/skins/dist/skin-yellow-dark.css new file mode 100644 index 0000000000..d2b48c86c1 Binary files /dev/null and b/public/css/skins/dist/skin-yellow-dark.css differ diff --git a/public/css/skins/dist/skin-yellow-dark.css.map b/public/css/skins/dist/skin-yellow-dark.css.map new file mode 100644 index 0000000000..0525871e8c Binary files /dev/null and b/public/css/skins/dist/skin-yellow-dark.css.map differ diff --git a/public/css/skins/dist/skin-yellow.css b/public/css/skins/dist/skin-yellow.css new file mode 100644 index 0000000000..21c58e7376 Binary files /dev/null and b/public/css/skins/dist/skin-yellow.css differ diff --git a/public/css/skins/dist/skin-yellow.css.map b/public/css/skins/dist/skin-yellow.css.map new file mode 100644 index 0000000000..86823cfb2f Binary files /dev/null and b/public/css/skins/dist/skin-yellow.css.map differ diff --git a/public/css/skins/skin-black-dark.css b/public/css/skins/skin-black-dark.css index d22a6b37eb..357442c6dc 100644 Binary files a/public/css/skins/skin-black-dark.css and b/public/css/skins/skin-black-dark.css differ diff --git a/public/css/skins/skin-black-dark.css.map b/public/css/skins/skin-black-dark.css.map index 09af319a55..af8a5ef671 100644 Binary files a/public/css/skins/skin-black-dark.css.map and b/public/css/skins/skin-black-dark.css.map differ diff --git a/public/css/skins/skin-black-light.css b/public/css/skins/skin-black-light.css deleted file mode 100644 index e9207d6971..0000000000 Binary files a/public/css/skins/skin-black-light.css and /dev/null differ diff --git a/public/css/skins/skin-black.css b/public/css/skins/skin-black.css index 7ab781a3cc..320500647f 100644 Binary files a/public/css/skins/skin-black.css and b/public/css/skins/skin-black.css differ diff --git a/public/css/skins/skin-black.css.map b/public/css/skins/skin-black.css.map index bc88731841..c816e2cbcc 100644 Binary files a/public/css/skins/skin-black.css.map and b/public/css/skins/skin-black.css.map differ diff --git a/public/css/skins/skin-blue-dark.css b/public/css/skins/skin-blue-dark.css index 4fb03f307a..7417af29f9 100644 Binary files a/public/css/skins/skin-blue-dark.css and b/public/css/skins/skin-blue-dark.css differ diff --git a/public/css/skins/skin-blue-dark.css.map b/public/css/skins/skin-blue-dark.css.map index a96985c1e8..b5558dec7b 100644 Binary files a/public/css/skins/skin-blue-dark.css.map and b/public/css/skins/skin-blue-dark.css.map differ diff --git a/public/css/skins/skin-blue-light.css b/public/css/skins/skin-blue-light.css deleted file mode 100755 index e6d038deda..0000000000 Binary files a/public/css/skins/skin-blue-light.css and /dev/null differ diff --git a/public/css/skins/skin-blue-light.css.map b/public/css/skins/skin-blue-light.css.map deleted file mode 100644 index 16a0ff494f..0000000000 Binary files a/public/css/skins/skin-blue-light.css.map and /dev/null differ diff --git a/public/css/skins/skin-blue-light.min.css b/public/css/skins/skin-blue-light.min.css deleted file mode 100755 index 4fab22a553..0000000000 Binary files a/public/css/skins/skin-blue-light.min.css and /dev/null differ diff --git a/public/css/skins/skin-blue.css b/public/css/skins/skin-blue.css old mode 100755 new mode 100644 index 3770566a60..c023dbbbfb Binary files a/public/css/skins/skin-blue.css and b/public/css/skins/skin-blue.css differ diff --git a/public/css/skins/skin-blue.css.map b/public/css/skins/skin-blue.css.map index 7e9917066a..01a028ec3e 100644 Binary files a/public/css/skins/skin-blue.css.map and b/public/css/skins/skin-blue.css.map differ diff --git a/public/css/skins/skin-green-dark.css b/public/css/skins/skin-green-dark.css index 97a65e83a8..cf08fa534f 100644 Binary files a/public/css/skins/skin-green-dark.css and b/public/css/skins/skin-green-dark.css differ diff --git a/public/css/skins/skin-green-dark.css.map b/public/css/skins/skin-green-dark.css.map index 573b3b2365..581b48f69b 100644 Binary files a/public/css/skins/skin-green-dark.css.map and b/public/css/skins/skin-green-dark.css.map differ diff --git a/public/css/skins/skin-green-light.css b/public/css/skins/skin-green-light.css deleted file mode 100644 index de95e390cf..0000000000 Binary files a/public/css/skins/skin-green-light.css and /dev/null differ diff --git a/public/css/skins/skin-green-light.css.map b/public/css/skins/skin-green-light.css.map deleted file mode 100644 index 494f2eb93c..0000000000 Binary files a/public/css/skins/skin-green-light.css.map and /dev/null differ diff --git a/public/css/skins/skin-green.css b/public/css/skins/skin-green.css index f2aaed4989..713e7ada12 100644 Binary files a/public/css/skins/skin-green.css and b/public/css/skins/skin-green.css differ diff --git a/public/css/skins/skin-green.css.map b/public/css/skins/skin-green.css.map index c496b1fade..223ed62e3f 100644 Binary files a/public/css/skins/skin-green.css.map and b/public/css/skins/skin-green.css.map differ diff --git a/public/css/skins/skin-orange-dark.css b/public/css/skins/skin-orange-dark.css index c52137b9f8..1c165c1293 100644 Binary files a/public/css/skins/skin-orange-dark.css and b/public/css/skins/skin-orange-dark.css differ diff --git a/public/css/skins/skin-orange-dark.css.map b/public/css/skins/skin-orange-dark.css.map index 880c6f3832..7aa0b7e06e 100644 Binary files a/public/css/skins/skin-orange-dark.css.map and b/public/css/skins/skin-orange-dark.css.map differ diff --git a/public/css/skins/skin-orange-light.css b/public/css/skins/skin-orange-light.css deleted file mode 100644 index 59161aa07e..0000000000 Binary files a/public/css/skins/skin-orange-light.css and /dev/null differ diff --git a/public/css/skins/skin-orange-light.css.map b/public/css/skins/skin-orange-light.css.map deleted file mode 100644 index d1a02a188e..0000000000 Binary files a/public/css/skins/skin-orange-light.css.map and /dev/null differ diff --git a/public/css/skins/skin-orange.css b/public/css/skins/skin-orange.css index f28dc22e23..7f5f69e8b3 100644 Binary files a/public/css/skins/skin-orange.css and b/public/css/skins/skin-orange.css differ diff --git a/public/css/skins/skin-orange.css.map b/public/css/skins/skin-orange.css.map index c9a51ddae1..6908ae29ac 100644 Binary files a/public/css/skins/skin-orange.css.map and b/public/css/skins/skin-orange.css.map differ diff --git a/public/css/skins/skin-purple-dark.css b/public/css/skins/skin-purple-dark.css index a6bc3910c2..86c12b1339 100644 Binary files a/public/css/skins/skin-purple-dark.css and b/public/css/skins/skin-purple-dark.css differ diff --git a/public/css/skins/skin-purple-dark.css.map b/public/css/skins/skin-purple-dark.css.map index 256beaa258..d8ecd5964a 100644 Binary files a/public/css/skins/skin-purple-dark.css.map and b/public/css/skins/skin-purple-dark.css.map differ diff --git a/public/css/skins/skin-purple-light.css b/public/css/skins/skin-purple-light.css deleted file mode 100644 index 5b92d0d4e3..0000000000 Binary files a/public/css/skins/skin-purple-light.css and /dev/null differ diff --git a/public/css/skins/skin-purple.css b/public/css/skins/skin-purple.css index 3add1e6532..dce5507013 100644 Binary files a/public/css/skins/skin-purple.css and b/public/css/skins/skin-purple.css differ diff --git a/public/css/skins/skin-purple.css.map b/public/css/skins/skin-purple.css.map index 71282a3b96..e46f0821d0 100644 Binary files a/public/css/skins/skin-purple.css.map and b/public/css/skins/skin-purple.css.map differ diff --git a/public/css/skins/skin-red-dark.css b/public/css/skins/skin-red-dark.css index daf7397353..5c64e60b45 100644 Binary files a/public/css/skins/skin-red-dark.css and b/public/css/skins/skin-red-dark.css differ diff --git a/public/css/skins/skin-red-dark.css.map b/public/css/skins/skin-red-dark.css.map index 822531a65b..d3c8f4b7d2 100644 Binary files a/public/css/skins/skin-red-dark.css.map and b/public/css/skins/skin-red-dark.css.map differ diff --git a/public/css/skins/skin-red-light.css b/public/css/skins/skin-red-light.css deleted file mode 100644 index 38f65f43a8..0000000000 Binary files a/public/css/skins/skin-red-light.css and /dev/null differ diff --git a/public/css/skins/skin-red-light.css.map b/public/css/skins/skin-red-light.css.map deleted file mode 100644 index f78bf00c0e..0000000000 Binary files a/public/css/skins/skin-red-light.css.map and /dev/null differ diff --git a/public/css/skins/skin-red.css b/public/css/skins/skin-red.css index dd59817cb4..0670a5689f 100644 Binary files a/public/css/skins/skin-red.css and b/public/css/skins/skin-red.css differ diff --git a/public/css/skins/skin-red.css.map b/public/css/skins/skin-red.css.map index b001c92028..ca724238e7 100644 Binary files a/public/css/skins/skin-red.css.map and b/public/css/skins/skin-red.css.map differ diff --git a/public/css/skins/skin-yellow-dark.css b/public/css/skins/skin-yellow-dark.css index 1a32940436..d2b48c86c1 100644 Binary files a/public/css/skins/skin-yellow-dark.css and b/public/css/skins/skin-yellow-dark.css differ diff --git a/public/css/skins/skin-yellow-dark.css.map b/public/css/skins/skin-yellow-dark.css.map index 6388cdb7e0..1373538523 100644 Binary files a/public/css/skins/skin-yellow-dark.css.map and b/public/css/skins/skin-yellow-dark.css.map differ diff --git a/public/css/skins/skin-yellow-light.css b/public/css/skins/skin-yellow-light.css deleted file mode 100644 index bbe217efd6..0000000000 Binary files a/public/css/skins/skin-yellow-light.css and /dev/null differ diff --git a/public/css/skins/skin-yellow-light.css.map b/public/css/skins/skin-yellow-light.css.map deleted file mode 100644 index ee77a60bb4..0000000000 Binary files a/public/css/skins/skin-yellow-light.css.map and /dev/null differ diff --git a/public/css/skins/skin-yellow.css b/public/css/skins/skin-yellow.css index f152d71fb5..21c58e7376 100644 Binary files a/public/css/skins/skin-yellow.css and b/public/css/skins/skin-yellow.css differ diff --git a/public/css/skins/skin-yellow.css.map b/public/css/skins/skin-yellow.css.map index d0a6fcce0d..981d3f7c95 100644 Binary files a/public/css/skins/skin-yellow.css.map and b/public/css/skins/skin-yellow.css.map differ diff --git a/public/img/demo/accessories/bluetooth.jpg b/public/img/demo/accessories/bluetooth.jpg new file mode 100644 index 0000000000..0d3558c4dc Binary files /dev/null and b/public/img/demo/accessories/bluetooth.jpg differ diff --git a/public/img/demo/accessories/comfort-mouse.jpg b/public/img/demo/accessories/comfort-mouse.jpg new file mode 100644 index 0000000000..6652da1189 Binary files /dev/null and b/public/img/demo/accessories/comfort-mouse.jpg differ diff --git a/public/img/demo/accessories/magic-mouse.jpg b/public/img/demo/accessories/magic-mouse.jpg new file mode 100644 index 0000000000..b23683fb4b Binary files /dev/null and b/public/img/demo/accessories/magic-mouse.jpg differ diff --git a/public/img/demo/accessories/usb-keyboard.jpg b/public/img/demo/accessories/usb-keyboard.jpg new file mode 100644 index 0000000000..e87fa202a5 Binary files /dev/null and b/public/img/demo/accessories/usb-keyboard.jpg differ diff --git a/public/img/demo/logo.png b/public/img/demo/logo.png new file mode 100644 index 0000000000..423a5b7490 Binary files /dev/null and b/public/img/demo/logo.png differ diff --git a/public/img/favicon.ico b/public/img/favicon.ico new file mode 100644 index 0000000000..7b20fd4f6b Binary files /dev/null and b/public/img/favicon.ico differ diff --git a/public/img/logo.png b/public/img/logo.png new file mode 100644 index 0000000000..a33581ec75 Binary files /dev/null and b/public/img/logo.png differ diff --git a/public/js/app.js b/public/js/app.js deleted file mode 100755 index c874b80f7d..0000000000 Binary files a/public/js/app.js and /dev/null differ diff --git a/public/js/app.min.js b/public/js/app.min.js deleted file mode 100755 index 679f18f1b3..0000000000 Binary files a/public/js/app.min.js and /dev/null differ diff --git a/public/js/build/all.js b/public/js/build/all.js deleted file mode 100644 index 97e3483cab..0000000000 Binary files a/public/js/build/all.js and /dev/null differ diff --git a/public/js/build/app.js b/public/js/build/app.js new file mode 100644 index 0000000000..e1f8fd26dd Binary files /dev/null and b/public/js/build/app.js differ diff --git a/public/js/build/vendor.js b/public/js/build/vendor.js new file mode 100644 index 0000000000..906424623b Binary files /dev/null and b/public/js/build/vendor.js differ diff --git a/public/js/build/vue.js.map b/public/js/build/vue.js.map deleted file mode 100644 index 85e92cc512..0000000000 Binary files a/public/js/build/vue.js.map and /dev/null differ diff --git a/public/js/dist/all.js b/public/js/dist/all.js index 450dce89c6..7a65b8f60d 100644 Binary files a/public/js/dist/all.js and b/public/js/dist/all.js differ diff --git a/public/js/dist/bootstrap-table.js b/public/js/dist/bootstrap-table.js new file mode 100644 index 0000000000..066519c2b8 Binary files /dev/null and b/public/js/dist/bootstrap-table.js differ diff --git a/public/js/plugins/iCheck/all.css b/public/js/plugins/iCheck/all.css deleted file mode 100755 index 6439b7429b..0000000000 Binary files a/public/js/plugins/iCheck/all.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/_all.css b/public/js/plugins/iCheck/flat/_all.css deleted file mode 100755 index 21647b50d8..0000000000 Binary files a/public/js/plugins/iCheck/flat/_all.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/aero.css b/public/js/plugins/iCheck/flat/aero.css deleted file mode 100755 index 98fd65c8cc..0000000000 Binary files a/public/js/plugins/iCheck/flat/aero.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/aero.png b/public/js/plugins/iCheck/flat/aero.png deleted file mode 100755 index f4277aa4cf..0000000000 Binary files a/public/js/plugins/iCheck/flat/aero.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/aero@2x.png b/public/js/plugins/iCheck/flat/aero@2x.png deleted file mode 100755 index a9a749459d..0000000000 Binary files a/public/js/plugins/iCheck/flat/aero@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/blue.css b/public/js/plugins/iCheck/flat/blue.css deleted file mode 100755 index 07836749af..0000000000 Binary files a/public/js/plugins/iCheck/flat/blue.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/blue.png b/public/js/plugins/iCheck/flat/blue.png deleted file mode 100755 index 4b6ef9825e..0000000000 Binary files a/public/js/plugins/iCheck/flat/blue.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/blue@2x.png b/public/js/plugins/iCheck/flat/blue@2x.png deleted file mode 100755 index d52da05771..0000000000 Binary files a/public/js/plugins/iCheck/flat/blue@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/flat.css b/public/js/plugins/iCheck/flat/flat.css deleted file mode 100755 index 418620eebc..0000000000 Binary files a/public/js/plugins/iCheck/flat/flat.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/flat.png b/public/js/plugins/iCheck/flat/flat.png deleted file mode 100755 index 15af826e0a..0000000000 Binary files a/public/js/plugins/iCheck/flat/flat.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/flat@2x.png b/public/js/plugins/iCheck/flat/flat@2x.png deleted file mode 100755 index e70e438c5d..0000000000 Binary files a/public/js/plugins/iCheck/flat/flat@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/green.css b/public/js/plugins/iCheck/flat/green.css deleted file mode 100755 index c9d17c1609..0000000000 Binary files a/public/js/plugins/iCheck/flat/green.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/green.png b/public/js/plugins/iCheck/flat/green.png deleted file mode 100755 index 6b303fbead..0000000000 Binary files a/public/js/plugins/iCheck/flat/green.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/green@2x.png b/public/js/plugins/iCheck/flat/green@2x.png deleted file mode 100755 index 92b4411d90..0000000000 Binary files a/public/js/plugins/iCheck/flat/green@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/grey.css b/public/js/plugins/iCheck/flat/grey.css deleted file mode 100755 index a451650ef8..0000000000 Binary files a/public/js/plugins/iCheck/flat/grey.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/grey.png b/public/js/plugins/iCheck/flat/grey.png deleted file mode 100755 index c6e2873ed5..0000000000 Binary files a/public/js/plugins/iCheck/flat/grey.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/grey@2x.png b/public/js/plugins/iCheck/flat/grey@2x.png deleted file mode 100755 index 0b47b1c6d9..0000000000 Binary files a/public/js/plugins/iCheck/flat/grey@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/orange.css b/public/js/plugins/iCheck/flat/orange.css deleted file mode 100755 index 8c9c929773..0000000000 Binary files a/public/js/plugins/iCheck/flat/orange.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/orange.png b/public/js/plugins/iCheck/flat/orange.png deleted file mode 100755 index ec2532ebe4..0000000000 Binary files a/public/js/plugins/iCheck/flat/orange.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/orange@2x.png b/public/js/plugins/iCheck/flat/orange@2x.png deleted file mode 100755 index 9350b50624..0000000000 Binary files a/public/js/plugins/iCheck/flat/orange@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/pink.css b/public/js/plugins/iCheck/flat/pink.css deleted file mode 100755 index afa4956623..0000000000 Binary files a/public/js/plugins/iCheck/flat/pink.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/pink.png b/public/js/plugins/iCheck/flat/pink.png deleted file mode 100755 index 3e65d9dd62..0000000000 Binary files a/public/js/plugins/iCheck/flat/pink.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/pink@2x.png b/public/js/plugins/iCheck/flat/pink@2x.png deleted file mode 100755 index 281ba06bec..0000000000 Binary files a/public/js/plugins/iCheck/flat/pink@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/purple.css b/public/js/plugins/iCheck/flat/purple.css deleted file mode 100755 index a9760b36d2..0000000000 Binary files a/public/js/plugins/iCheck/flat/purple.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/purple.png b/public/js/plugins/iCheck/flat/purple.png deleted file mode 100755 index 3699fd5832..0000000000 Binary files a/public/js/plugins/iCheck/flat/purple.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/purple@2x.png b/public/js/plugins/iCheck/flat/purple@2x.png deleted file mode 100755 index 7f4be74a7c..0000000000 Binary files a/public/js/plugins/iCheck/flat/purple@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/red.css b/public/js/plugins/iCheck/flat/red.css deleted file mode 100755 index 34b71e4702..0000000000 Binary files a/public/js/plugins/iCheck/flat/red.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/red.png b/public/js/plugins/iCheck/flat/red.png deleted file mode 100755 index 0d5ac3819b..0000000000 Binary files a/public/js/plugins/iCheck/flat/red.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/red@2x.png b/public/js/plugins/iCheck/flat/red@2x.png deleted file mode 100755 index 38590d9852..0000000000 Binary files a/public/js/plugins/iCheck/flat/red@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/yellow.css b/public/js/plugins/iCheck/flat/yellow.css deleted file mode 100755 index 96ae5b1f9e..0000000000 Binary files a/public/js/plugins/iCheck/flat/yellow.css and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/yellow.png b/public/js/plugins/iCheck/flat/yellow.png deleted file mode 100755 index 909dadc529..0000000000 Binary files a/public/js/plugins/iCheck/flat/yellow.png and /dev/null differ diff --git a/public/js/plugins/iCheck/flat/yellow@2x.png b/public/js/plugins/iCheck/flat/yellow@2x.png deleted file mode 100755 index 9fd5d73393..0000000000 Binary files a/public/js/plugins/iCheck/flat/yellow@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/futurico/futurico.css b/public/js/plugins/iCheck/futurico/futurico.css deleted file mode 100755 index 2654cf4fe3..0000000000 Binary files a/public/js/plugins/iCheck/futurico/futurico.css and /dev/null differ diff --git a/public/js/plugins/iCheck/futurico/futurico.png b/public/js/plugins/iCheck/futurico/futurico.png deleted file mode 100755 index 50d62b5d40..0000000000 Binary files a/public/js/plugins/iCheck/futurico/futurico.png and /dev/null differ diff --git a/public/js/plugins/iCheck/futurico/futurico@2x.png b/public/js/plugins/iCheck/futurico/futurico@2x.png deleted file mode 100755 index f7eb45aad0..0000000000 Binary files a/public/js/plugins/iCheck/futurico/futurico@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/icheck.js b/public/js/plugins/iCheck/icheck.js deleted file mode 100755 index 4da1937ad4..0000000000 Binary files a/public/js/plugins/iCheck/icheck.js and /dev/null differ diff --git a/public/js/plugins/iCheck/icheck.min.js b/public/js/plugins/iCheck/icheck.min.js deleted file mode 100755 index d2720ed043..0000000000 Binary files a/public/js/plugins/iCheck/icheck.min.js and /dev/null differ diff --git a/public/js/plugins/iCheck/line/_all.css b/public/js/plugins/iCheck/line/_all.css deleted file mode 100755 index a18d0d90e8..0000000000 Binary files a/public/js/plugins/iCheck/line/_all.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/aero.css b/public/js/plugins/iCheck/line/aero.css deleted file mode 100755 index 44989a462e..0000000000 Binary files a/public/js/plugins/iCheck/line/aero.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/blue.css b/public/js/plugins/iCheck/line/blue.css deleted file mode 100755 index 5c9c0a7826..0000000000 Binary files a/public/js/plugins/iCheck/line/blue.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/green.css b/public/js/plugins/iCheck/line/green.css deleted file mode 100755 index 8bbe5140fc..0000000000 Binary files a/public/js/plugins/iCheck/line/green.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/grey.css b/public/js/plugins/iCheck/line/grey.css deleted file mode 100755 index fc16a80e29..0000000000 Binary files a/public/js/plugins/iCheck/line/grey.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/line.css b/public/js/plugins/iCheck/line/line.css deleted file mode 100755 index dbde8d4d8b..0000000000 Binary files a/public/js/plugins/iCheck/line/line.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/line.png b/public/js/plugins/iCheck/line/line.png deleted file mode 100755 index d21d7a7b43..0000000000 Binary files a/public/js/plugins/iCheck/line/line.png and /dev/null differ diff --git a/public/js/plugins/iCheck/line/line@2x.png b/public/js/plugins/iCheck/line/line@2x.png deleted file mode 100755 index 62900a2d93..0000000000 Binary files a/public/js/plugins/iCheck/line/line@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/line/orange.css b/public/js/plugins/iCheck/line/orange.css deleted file mode 100755 index 210f334014..0000000000 Binary files a/public/js/plugins/iCheck/line/orange.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/pink.css b/public/js/plugins/iCheck/line/pink.css deleted file mode 100755 index 44c9cea197..0000000000 Binary files a/public/js/plugins/iCheck/line/pink.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/purple.css b/public/js/plugins/iCheck/line/purple.css deleted file mode 100755 index be4c4e2bb5..0000000000 Binary files a/public/js/plugins/iCheck/line/purple.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/red.css b/public/js/plugins/iCheck/line/red.css deleted file mode 100755 index ebcd8befdb..0000000000 Binary files a/public/js/plugins/iCheck/line/red.css and /dev/null differ diff --git a/public/js/plugins/iCheck/line/yellow.css b/public/js/plugins/iCheck/line/yellow.css deleted file mode 100755 index 8e088714e2..0000000000 Binary files a/public/js/plugins/iCheck/line/yellow.css and /dev/null differ diff --git a/public/js/plugins/iCheck/minimal/_all.css b/public/js/plugins/iCheck/minimal/_all.css deleted file mode 100755 index b2165ecc35..0000000000 Binary files a/public/js/plugins/iCheck/minimal/_all.css and /dev/null differ diff --git a/public/js/plugins/iCheck/minimal/minimal.css b/public/js/plugins/iCheck/minimal/minimal.css deleted file mode 100755 index 7c0e52e1da..0000000000 Binary files a/public/js/plugins/iCheck/minimal/minimal.css and /dev/null differ diff --git a/public/js/plugins/iCheck/minimal/yellow.css b/public/js/plugins/iCheck/minimal/yellow.css deleted file mode 100755 index 2c38423130..0000000000 Binary files a/public/js/plugins/iCheck/minimal/yellow.css and /dev/null differ diff --git a/public/js/plugins/iCheck/polaris/polaris.css b/public/js/plugins/iCheck/polaris/polaris.css deleted file mode 100755 index 1cb4bcc0ec..0000000000 Binary files a/public/js/plugins/iCheck/polaris/polaris.css and /dev/null differ diff --git a/public/js/plugins/iCheck/polaris/polaris.png b/public/js/plugins/iCheck/polaris/polaris.png deleted file mode 100755 index 60c14e6a88..0000000000 Binary files a/public/js/plugins/iCheck/polaris/polaris.png and /dev/null differ diff --git a/public/js/plugins/iCheck/polaris/polaris@2x.png b/public/js/plugins/iCheck/polaris/polaris@2x.png deleted file mode 100755 index c75b82695d..0000000000 Binary files a/public/js/plugins/iCheck/polaris/polaris@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/_all.css b/public/js/plugins/iCheck/square/_all.css deleted file mode 100755 index a2ff036869..0000000000 Binary files a/public/js/plugins/iCheck/square/_all.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/aero.css b/public/js/plugins/iCheck/square/aero.css deleted file mode 100755 index 51fca0a81a..0000000000 Binary files a/public/js/plugins/iCheck/square/aero.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/aero.png b/public/js/plugins/iCheck/square/aero.png deleted file mode 100755 index 1a332e6c57..0000000000 Binary files a/public/js/plugins/iCheck/square/aero.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/aero@2x.png b/public/js/plugins/iCheck/square/aero@2x.png deleted file mode 100755 index 07c5a02248..0000000000 Binary files a/public/js/plugins/iCheck/square/aero@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/blue.css b/public/js/plugins/iCheck/square/blue.css deleted file mode 100755 index 95340fea27..0000000000 Binary files a/public/js/plugins/iCheck/square/blue.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/blue.png b/public/js/plugins/iCheck/square/blue.png deleted file mode 100755 index a3e040fcce..0000000000 Binary files a/public/js/plugins/iCheck/square/blue.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/blue@2x.png b/public/js/plugins/iCheck/square/blue@2x.png deleted file mode 100755 index 8fdea12f96..0000000000 Binary files a/public/js/plugins/iCheck/square/blue@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/green.css b/public/js/plugins/iCheck/square/green.css deleted file mode 100755 index eb43f2a426..0000000000 Binary files a/public/js/plugins/iCheck/square/green.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/green.png b/public/js/plugins/iCheck/square/green.png deleted file mode 100755 index 465824e70c..0000000000 Binary files a/public/js/plugins/iCheck/square/green.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/green@2x.png b/public/js/plugins/iCheck/square/green@2x.png deleted file mode 100755 index 784e874758..0000000000 Binary files a/public/js/plugins/iCheck/square/green@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/grey.css b/public/js/plugins/iCheck/square/grey.css deleted file mode 100755 index ecc57ff43d..0000000000 Binary files a/public/js/plugins/iCheck/square/grey.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/grey.png b/public/js/plugins/iCheck/square/grey.png deleted file mode 100755 index f69375854d..0000000000 Binary files a/public/js/plugins/iCheck/square/grey.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/grey@2x.png b/public/js/plugins/iCheck/square/grey@2x.png deleted file mode 100755 index 5d6341c053..0000000000 Binary files a/public/js/plugins/iCheck/square/grey@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/orange.css b/public/js/plugins/iCheck/square/orange.css deleted file mode 100755 index d0c7a2cf24..0000000000 Binary files a/public/js/plugins/iCheck/square/orange.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/orange.png b/public/js/plugins/iCheck/square/orange.png deleted file mode 100755 index 84608500a6..0000000000 Binary files a/public/js/plugins/iCheck/square/orange.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/orange@2x.png b/public/js/plugins/iCheck/square/orange@2x.png deleted file mode 100755 index b1f2319735..0000000000 Binary files a/public/js/plugins/iCheck/square/orange@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/pink.css b/public/js/plugins/iCheck/square/pink.css deleted file mode 100755 index 6b706f6db4..0000000000 Binary files a/public/js/plugins/iCheck/square/pink.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/pink.png b/public/js/plugins/iCheck/square/pink.png deleted file mode 100755 index 9c8b4e2b6c..0000000000 Binary files a/public/js/plugins/iCheck/square/pink.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/pink@2x.png b/public/js/plugins/iCheck/square/pink@2x.png deleted file mode 100755 index b1f3a6eda6..0000000000 Binary files a/public/js/plugins/iCheck/square/pink@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/purple.css b/public/js/plugins/iCheck/square/purple.css deleted file mode 100755 index 43051d3db9..0000000000 Binary files a/public/js/plugins/iCheck/square/purple.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/purple.png b/public/js/plugins/iCheck/square/purple.png deleted file mode 100755 index 6bfc16a38c..0000000000 Binary files a/public/js/plugins/iCheck/square/purple.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/purple@2x.png b/public/js/plugins/iCheck/square/purple@2x.png deleted file mode 100755 index 6d3c8b1af3..0000000000 Binary files a/public/js/plugins/iCheck/square/purple@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/red.css b/public/js/plugins/iCheck/square/red.css deleted file mode 100755 index 40013c427b..0000000000 Binary files a/public/js/plugins/iCheck/square/red.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/red.png b/public/js/plugins/iCheck/square/red.png deleted file mode 100755 index 749675a979..0000000000 Binary files a/public/js/plugins/iCheck/square/red.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/red@2x.png b/public/js/plugins/iCheck/square/red@2x.png deleted file mode 100755 index c05700a574..0000000000 Binary files a/public/js/plugins/iCheck/square/red@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/square.css b/public/js/plugins/iCheck/square/square.css deleted file mode 100755 index b604fa84fe..0000000000 Binary files a/public/js/plugins/iCheck/square/square.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/square.png b/public/js/plugins/iCheck/square/square.png deleted file mode 100755 index 2a3c88116c..0000000000 Binary files a/public/js/plugins/iCheck/square/square.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/square@2x.png b/public/js/plugins/iCheck/square/square@2x.png deleted file mode 100755 index 9b56c448d0..0000000000 Binary files a/public/js/plugins/iCheck/square/square@2x.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/yellow.css b/public/js/plugins/iCheck/square/yellow.css deleted file mode 100755 index 551134992d..0000000000 Binary files a/public/js/plugins/iCheck/square/yellow.css and /dev/null differ diff --git a/public/js/plugins/iCheck/square/yellow.png b/public/js/plugins/iCheck/square/yellow.png deleted file mode 100755 index b6c0330909..0000000000 Binary files a/public/js/plugins/iCheck/square/yellow.png and /dev/null differ diff --git a/public/js/plugins/iCheck/square/yellow@2x.png b/public/js/plugins/iCheck/square/yellow@2x.png deleted file mode 100755 index 6b8e328e1a..0000000000 Binary files a/public/js/plugins/iCheck/square/yellow@2x.png and /dev/null differ diff --git a/public/js/plugins/select2/select2.css b/public/js/plugins/select2/select2.css index d365213c7b..125a15d72e 100755 Binary files a/public/js/plugins/select2/select2.css and b/public/js/plugins/select2/select2.css differ diff --git a/public/js/snipeit.js b/public/js/snipeit.js new file mode 100644 index 0000000000..2be8145758 Binary files /dev/null and b/public/js/snipeit.js differ diff --git a/public/js/vendor.js b/public/js/vendor.js new file mode 100644 index 0000000000..2abcea1773 Binary files /dev/null and b/public/js/vendor.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index b31c6118a5..1ab25dd920 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,44 +1,38 @@ { - "/js/build/vue.js": "/js/build/vue.js?id=aff26ce7202625817ca1", - "/css/AdminLTE.css": "/css/AdminLTE.css?id=56b8066cfbc70df10545", - "/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405", - "/css/overrides.css": "/css/overrides.css?id=d1fe6296eb548247a5ad", - "/css/skins/skin-blue.css": "/css/skins/skin-blue.css?id=c28283a1d468e2337428", - "/css/skins/skin-red.css": "/css/skins/skin-red.css?id=079dd6c501fa9ea60a98", - "/css/skins/skin-contrast.css": "/css/skins/skin-contrast.css?id=62e14190151e9efc9995", - "/css/skins/skin-green.css": "/css/skins/skin-green.css?id=2c53f7ed585fcad563b2", - "/css/skins/skin-green-dark.css": "/css/skins/skin-green-dark.css?id=cb34691dbbb72cae7f5f", - "/css/skins/skin-black.css": "/css/skins/skin-black.css?id=1dfec89b8640b69dc0fc", - "/css/skins/skin-black-dark.css": "/css/skins/skin-black-dark.css?id=2729852ce23eb6c53e1f", - "/css/skins/skin-red-dark.css": "/css/skins/skin-red-dark.css?id=5c8c8a8612f7f6d249e9", - "/css/skins/skin-purple.css": "/css/skins/skin-purple.css?id=c70f96a9bd3c18264998", - "/css/skins/skin-purple-dark.css": "/css/skins/skin-purple-dark.css?id=ac1bf57c994303df68f9", - "/css/skins/skin-yellow.css": "/css/skins/skin-yellow.css?id=4861a639314b1685a5b9", - "/css/skins/skin-yellow-dark.css": "/css/skins/skin-yellow-dark.css?id=ef5c5bffa1729937cbda", - "/css/skins/skin-blue-dark.css": "/css/skins/skin-blue-dark.css?id=d25c77d9c6f4cfe2efd4", - "/css/skins/skin-orange-dark.css": "/css/skins/skin-orange-dark.css?id=abc219c1fed59cecb860", - "/css/skins/skin-orange.css": "/css/skins/skin-orange.css?id=59664dbd286988d2a438", - "/js/build/vue.js.map": "/js/build/vue.js.map?id=41a870ef3b9b5c6688ca", - "/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=5a2d6f3c59191ce716e2", - "/css/app.css.map": "/css/app.css.map?id=96b5c985e860716e6a16", - "/css/overrides.css.map": "/css/overrides.css.map?id=f3e3cf42859eb4a28a7b", - "/css/skins/skin-blue.css.map": "/css/skins/skin-blue.css.map?id=129b9523e6ffd5683230", - "/css/skins/skin-red.css.map": "/css/skins/skin-red.css.map?id=292dfa49bf2b6f23fa59", - "/css/skins/skin-contrast.css.map": "/css/skins/skin-contrast.css.map?id=bf37f812f0b6a109b5ce", - "/css/skins/skin-green.css.map": "/css/skins/skin-green.css.map?id=50461604ff9b1934d580", - "/css/skins/skin-green-dark.css.map": "/css/skins/skin-green-dark.css.map?id=988cf7da13d22c56bd8c", - "/css/skins/skin-black.css.map": "/css/skins/skin-black.css.map?id=ad0bf20283280a01b34f", - "/css/skins/skin-black-dark.css.map": "/css/skins/skin-black-dark.css.map?id=f15511c14609c70c641f", - "/css/skins/skin-red-dark.css.map": "/css/skins/skin-red-dark.css.map?id=de49574e94466ac1b2c5", - "/css/skins/skin-purple.css.map": "/css/skins/skin-purple.css.map?id=98a83bd7f857ca052319", - "/css/skins/skin-purple-dark.css.map": "/css/skins/skin-purple-dark.css.map?id=9bd3178f252823e99c70", - "/css/skins/skin-yellow.css.map": "/css/skins/skin-yellow.css.map?id=c9fcf2ca55e830230e18", - "/css/skins/skin-yellow-dark.css.map": "/css/skins/skin-yellow-dark.css.map?id=8ef6b327183be556c708", - "/css/skins/skin-blue-dark.css.map": "/css/skins/skin-blue-dark.css.map?id=32784cb5d02773eb0e69", - "/css/skins/skin-orange-dark.css.map": "/css/skins/skin-orange-dark.css.map?id=68b998638217fd08ef29", - "/css/skins/skin-orange.css.map": "/css/skins/skin-orange.css.map?id=f90fda3cc0a48c048a9e", - "/css/dist/all.css": "/css/dist/all.css?id=0491555899142b86167d", - "/js/dist/all.js": "/js/dist/all.js?id=5ac062af7b26fb838213", - "/css/build/all.css": "/css/build/all.css?id=0491555899142b86167d", - "/js/build/all.js": "/js/build/all.js?id=5ac062af7b26fb838213" + "/js/build/app.js": "/js/build/app.js?id=edf4823a58f20c4e41fc", + "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=59413334823616b81341", + "/css/build/app.css": "/css/build/app.css?id=032fd8c3fce99c7fd862", + "/css/build/overrides.css": "/css/build/overrides.css?id=0b4aefd7ef0c117ef23a", + "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=9fa704134cfacfacab93", + "/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=747948e5f269f64047f7", + "/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=d7996d850e8bcdc4e167", + "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=eb25d2ec49f730d09431", + "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=0cfa39cacd9c83b4f53b", + "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=35602987835e5d50d162", + "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=6bd9c2420a41eaf96f0b", + "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=60de5bc2660c35544c4d", + "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=b6dcb6d5c666fc5c8cc0", + "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=9dd1dc817a71431e5904", + "/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=cb85a4e40e784319e878", + "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=4a19f5ae861f98f40bab", + "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=2f665cf40d7348b3f94c", + "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=71c178700d68294e3413", + "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=b4fc4a74e1f6367dc3e2", + "/css/dist/all.css": "/css/dist/all.css?id=23029d15778815d3c35a", + "/css/blue.png": "/css/blue.png?id=4c85d6a97173123bd14a", + "/css/blue@2x.png": "/css/blue@2x.png?id=62c67c6a822439e8a4ac", + "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0cfa39cacd9c83b4f53b", + "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=6bd9c2420a41eaf96f0b", + "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=2f665cf40d7348b3f94c", + "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=4a19f5ae861f98f40bab", + "/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=60de5bc2660c35544c4d", + "/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=9dd1dc817a71431e5904", + "/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=71c178700d68294e3413", + "/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=d7996d850e8bcdc4e167", + "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced", + "/css/build/signature-pad.min.css": "/css/build/signature-pad.min.css?id=d41d8cd98f00b204e980", + "/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=a534edb9f7179f6dcf62", + "/js/build/vendor.js": "/js/build/vendor.js?id=ac70ab5fd89efc2aa7d0", + "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=9407782198cbc29f23d1", + "/js/dist/all.js": "/js/dist/all.js?id=29881ddb42a1bf849280" } diff --git a/public/mix.js.map b/public/mix.js.map new file mode 100644 index 0000000000..11feb36568 --- /dev/null +++ b/public/mix.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap 59d0be0e604d88b50a4b"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s"],"mappings":"aACA,IAAAA,KAGA,SAAAC,EAAAC,GAGA,GAAAF,EAAAE,GACA,OAAAF,EAAAE,GAAAC,QAGA,IAAAC,EAAAJ,EAAAE,IACAG,EAAAH,EACAI,GAAA,EACAH,YAUA,OANAI,EAAAL,GAAAM,KAAAJ,EAAAD,QAAAC,IAAAD,QAAAF,GAGAG,EAAAE,GAAA,EAGAF,EAAAD,QAKAF,EAAAQ,EAAAF,EAGAN,EAAAS,EAAAV,EAGAC,EAAAU,EAAA,SAAAR,EAAAS,EAAAC,GACAZ,EAAAa,EAAAX,EAAAS,IACAG,OAAAC,eAAAb,EAAAS,GACAK,cAAA,EACAC,YAAA,EACAC,IAAAN,KAMAZ,EAAAmB,EAAA,SAAAhB,GACA,IAAAS,EAAAT,KAAAiB,WACA,WAA2B,OAAAjB,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAH,EAAAU,EAAAE,EAAA,IAAAA,GACAA,GAIAZ,EAAAa,EAAA,SAAAQ,EAAAC,GAAsD,OAAAR,OAAAS,UAAAC,eAAAjB,KAAAc,EAAAC,IAGtDtB,EAAAyB,EAAA,IAGAzB,IAAA0B,EAAA","file":"mix.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 59d0be0e604d88b50a4b"],"sourceRoot":""} \ No newline at end of file diff --git a/public/uploads/.gitignore b/public/uploads/.gitignore index f935021a8f..73edf0327e 100755 --- a/public/uploads/.gitignore +++ b/public/uploads/.gitignore @@ -1 +1,2 @@ !.gitignore +* \ No newline at end of file diff --git a/resources/assets/css/app.css b/resources/assets/css/app.css deleted file mode 100644 index 89a60fedb2..0000000000 --- a/resources/assets/css/app.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{background:transparent!important;color:#000!important;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:Glyphicons Halflings;src:url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.eot");src:url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"),url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.woff2") format("woff2"),url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.woff") format("woff"),url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.ttf") format("truetype"),url("../../../node_modules/bootstrap-less/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg")}.glyphicon{position:relative;top:1px;display:inline-block;font-family:Glyphicons Halflings;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"*"}.glyphicon-plus:before{content:"+"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20AC"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270F"}.glyphicon-glass:before{content:"\E001"}.glyphicon-music:before{content:"\E002"}.glyphicon-search:before{content:"\E003"}.glyphicon-heart:before{content:"\E005"}.glyphicon-star:before{content:"\E006"}.glyphicon-star-empty:before{content:"\E007"}.glyphicon-user:before{content:"\E008"}.glyphicon-film:before{content:"\E009"}.glyphicon-th-large:before{content:"\E010"}.glyphicon-th:before{content:"\E011"}.glyphicon-th-list:before{content:"\E012"}.glyphicon-ok:before{content:"\E013"}.glyphicon-remove:before{content:"\E014"}.glyphicon-zoom-in:before{content:"\E015"}.glyphicon-zoom-out:before{content:"\E016"}.glyphicon-off:before{content:"\E017"}.glyphicon-signal:before{content:"\E018"}.glyphicon-cog:before{content:"\E019"}.glyphicon-trash:before{content:"\E020"}.glyphicon-home:before{content:"\E021"}.glyphicon-file:before{content:"\E022"}.glyphicon-time:before{content:"\E023"}.glyphicon-road:before{content:"\E024"}.glyphicon-download-alt:before{content:"\E025"}.glyphicon-download:before{content:"\E026"}.glyphicon-upload:before{content:"\E027"}.glyphicon-inbox:before{content:"\E028"}.glyphicon-play-circle:before{content:"\E029"}.glyphicon-repeat:before{content:"\E030"}.glyphicon-refresh:before{content:"\E031"}.glyphicon-list-alt:before{content:"\E032"}.glyphicon-lock:before{content:"\E033"}.glyphicon-flag:before{content:"\E034"}.glyphicon-headphones:before{content:"\E035"}.glyphicon-volume-off:before{content:"\E036"}.glyphicon-volume-down:before{content:"\E037"}.glyphicon-volume-up:before{content:"\E038"}.glyphicon-qrcode:before{content:"\E039"}.glyphicon-barcode:before{content:"\E040"}.glyphicon-tag:before{content:"\E041"}.glyphicon-tags:before{content:"\E042"}.glyphicon-book:before{content:"\E043"}.glyphicon-bookmark:before{content:"\E044"}.glyphicon-print:before{content:"\E045"}.glyphicon-camera:before{content:"\E046"}.glyphicon-font:before{content:"\E047"}.glyphicon-bold:before{content:"\E048"}.glyphicon-italic:before{content:"\E049"}.glyphicon-text-height:before{content:"\E050"}.glyphicon-text-width:before{content:"\E051"}.glyphicon-align-left:before{content:"\E052"}.glyphicon-align-center:before{content:"\E053"}.glyphicon-align-right:before{content:"\E054"}.glyphicon-align-justify:before{content:"\E055"}.glyphicon-list:before{content:"\E056"}.glyphicon-indent-left:before{content:"\E057"}.glyphicon-indent-right:before{content:"\E058"}.glyphicon-facetime-video:before{content:"\E059"}.glyphicon-picture:before{content:"\E060"}.glyphicon-map-marker:before{content:"\E062"}.glyphicon-adjust:before{content:"\E063"}.glyphicon-tint:before{content:"\E064"}.glyphicon-edit:before{content:"\E065"}.glyphicon-share:before{content:"\E066"}.glyphicon-check:before{content:"\E067"}.glyphicon-move:before{content:"\E068"}.glyphicon-step-backward:before{content:"\E069"}.glyphicon-fast-backward:before{content:"\E070"}.glyphicon-backward:before{content:"\E071"}.glyphicon-play:before{content:"\E072"}.glyphicon-pause:before{content:"\E073"}.glyphicon-stop:before{content:"\E074"}.glyphicon-forward:before{content:"\E075"}.glyphicon-fast-forward:before{content:"\E076"}.glyphicon-step-forward:before{content:"\E077"}.glyphicon-eject:before{content:"\E078"}.glyphicon-chevron-left:before{content:"\E079"}.glyphicon-chevron-right:before{content:"\E080"}.glyphicon-plus-sign:before{content:"\E081"}.glyphicon-minus-sign:before{content:"\E082"}.glyphicon-remove-sign:before{content:"\E083"}.glyphicon-ok-sign:before{content:"\E084"}.glyphicon-question-sign:before{content:"\E085"}.glyphicon-info-sign:before{content:"\E086"}.glyphicon-screenshot:before{content:"\E087"}.glyphicon-remove-circle:before{content:"\E088"}.glyphicon-ok-circle:before{content:"\E089"}.glyphicon-ban-circle:before{content:"\E090"}.glyphicon-arrow-left:before{content:"\E091"}.glyphicon-arrow-right:before{content:"\E092"}.glyphicon-arrow-up:before{content:"\E093"}.glyphicon-arrow-down:before{content:"\E094"}.glyphicon-share-alt:before{content:"\E095"}.glyphicon-resize-full:before{content:"\E096"}.glyphicon-resize-small:before{content:"\E097"}.glyphicon-exclamation-sign:before{content:"\E101"}.glyphicon-gift:before{content:"\E102"}.glyphicon-leaf:before{content:"\E103"}.glyphicon-fire:before{content:"\E104"}.glyphicon-eye-open:before{content:"\E105"}.glyphicon-eye-close:before{content:"\E106"}.glyphicon-warning-sign:before{content:"\E107"}.glyphicon-plane:before{content:"\E108"}.glyphicon-calendar:before{content:"\E109"}.glyphicon-random:before{content:"\E110"}.glyphicon-comment:before{content:"\E111"}.glyphicon-magnet:before{content:"\E112"}.glyphicon-chevron-up:before{content:"\E113"}.glyphicon-chevron-down:before{content:"\E114"}.glyphicon-retweet:before{content:"\E115"}.glyphicon-shopping-cart:before{content:"\E116"}.glyphicon-folder-close:before{content:"\E117"}.glyphicon-folder-open:before{content:"\E118"}.glyphicon-resize-vertical:before{content:"\E119"}.glyphicon-resize-horizontal:before{content:"\E120"}.glyphicon-hdd:before{content:"\E121"}.glyphicon-bullhorn:before{content:"\E122"}.glyphicon-bell:before{content:"\E123"}.glyphicon-certificate:before{content:"\E124"}.glyphicon-thumbs-up:before{content:"\E125"}.glyphicon-thumbs-down:before{content:"\E126"}.glyphicon-hand-right:before{content:"\E127"}.glyphicon-hand-left:before{content:"\E128"}.glyphicon-hand-up:before{content:"\E129"}.glyphicon-hand-down:before{content:"\E130"}.glyphicon-circle-arrow-right:before{content:"\E131"}.glyphicon-circle-arrow-left:before{content:"\E132"}.glyphicon-circle-arrow-up:before{content:"\E133"}.glyphicon-circle-arrow-down:before{content:"\E134"}.glyphicon-globe:before{content:"\E135"}.glyphicon-wrench:before{content:"\E136"}.glyphicon-tasks:before{content:"\E137"}.glyphicon-filter:before{content:"\E138"}.glyphicon-briefcase:before{content:"\E139"}.glyphicon-fullscreen:before{content:"\E140"}.glyphicon-dashboard:before{content:"\E141"}.glyphicon-paperclip:before{content:"\E142"}.glyphicon-heart-empty:before{content:"\E143"}.glyphicon-link:before{content:"\E144"}.glyphicon-phone:before{content:"\E145"}.glyphicon-pushpin:before{content:"\E146"}.glyphicon-usd:before{content:"\E148"}.glyphicon-gbp:before{content:"\E149"}.glyphicon-sort:before{content:"\E150"}.glyphicon-sort-by-alphabet:before{content:"\E151"}.glyphicon-sort-by-alphabet-alt:before{content:"\E152"}.glyphicon-sort-by-order:before{content:"\E153"}.glyphicon-sort-by-order-alt:before{content:"\E154"}.glyphicon-sort-by-attributes:before{content:"\E155"}.glyphicon-sort-by-attributes-alt:before{content:"\E156"}.glyphicon-unchecked:before{content:"\E157"}.glyphicon-expand:before{content:"\E158"}.glyphicon-collapse-down:before{content:"\E159"}.glyphicon-collapse-up:before{content:"\E160"}.glyphicon-log-in:before{content:"\E161"}.glyphicon-flash:before{content:"\E162"}.glyphicon-log-out:before{content:"\E163"}.glyphicon-new-window:before{content:"\E164"}.glyphicon-record:before{content:"\E165"}.glyphicon-save:before{content:"\E166"}.glyphicon-open:before{content:"\E167"}.glyphicon-saved:before{content:"\E168"}.glyphicon-import:before{content:"\E169"}.glyphicon-export:before{content:"\E170"}.glyphicon-send:before{content:"\E171"}.glyphicon-floppy-disk:before{content:"\E172"}.glyphicon-floppy-saved:before{content:"\E173"}.glyphicon-floppy-remove:before{content:"\E174"}.glyphicon-floppy-save:before{content:"\E175"}.glyphicon-floppy-open:before{content:"\E176"}.glyphicon-credit-card:before{content:"\E177"}.glyphicon-transfer:before{content:"\E178"}.glyphicon-cutlery:before{content:"\E179"}.glyphicon-header:before{content:"\E180"}.glyphicon-compressed:before{content:"\E181"}.glyphicon-earphone:before{content:"\E182"}.glyphicon-phone-alt:before{content:"\E183"}.glyphicon-tower:before{content:"\E184"}.glyphicon-stats:before{content:"\E185"}.glyphicon-sd-video:before{content:"\E186"}.glyphicon-hd-video:before{content:"\E187"}.glyphicon-subtitles:before{content:"\E188"}.glyphicon-sound-stereo:before{content:"\E189"}.glyphicon-sound-dolby:before{content:"\E190"}.glyphicon-sound-5-1:before{content:"\E191"}.glyphicon-sound-6-1:before{content:"\E192"}.glyphicon-sound-7-1:before{content:"\E193"}.glyphicon-copyright-mark:before{content:"\E194"}.glyphicon-registration-mark:before{content:"\E195"}.glyphicon-cloud-download:before{content:"\E197"}.glyphicon-cloud-upload:before{content:"\E198"}.glyphicon-tree-conifer:before{content:"\E199"}.glyphicon-tree-deciduous:before{content:"\E200"}.glyphicon-cd:before{content:"\E201"}.glyphicon-save-file:before{content:"\E202"}.glyphicon-open-file:before{content:"\E203"}.glyphicon-level-up:before{content:"\E204"}.glyphicon-copy:before{content:"\E205"}.glyphicon-paste:before{content:"\E206"}.glyphicon-alert:before{content:"\E209"}.glyphicon-equalizer:before{content:"\E210"}.glyphicon-king:before{content:"\E211"}.glyphicon-queen:before{content:"\E212"}.glyphicon-pawn:before{content:"\E213"}.glyphicon-bishop:before{content:"\E214"}.glyphicon-knight:before{content:"\E215"}.glyphicon-baby-formula:before{content:"\E216"}.glyphicon-tent:before{content:"\26FA"}.glyphicon-blackboard:before{content:"\E218"}.glyphicon-bed:before{content:"\E219"}.glyphicon-apple:before{content:"\F8FF"}.glyphicon-erase:before{content:"\E221"}.glyphicon-hourglass:before{content:"\231B"}.glyphicon-lamp:before{content:"\E223"}.glyphicon-duplicate:before{content:"\E224"}.glyphicon-piggy-bank:before{content:"\E225"}.glyphicon-scissors:before{content:"\E226"}.glyphicon-bitcoin:before{content:"\E227"}.glyphicon-yen:before{content:"\A5"}.glyphicon-ruble:before{content:"\20BD"}.glyphicon-scale:before{content:"\E230"}.glyphicon-ice-lolly:before{content:"\E231"}.glyphicon-ice-lolly-tasted:before{content:"\E232"}.glyphicon-education:before{content:"\E233"}.glyphicon-option-horizontal:before{content:"\E234"}.glyphicon-option-vertical:before{content:"\E235"}.glyphicon-menu-hamburger:before{content:"\E236"}.glyphicon-modal-window:before{content:"\E237"}.glyphicon-oil:before{content:"\E238"}.glyphicon-grain:before{content:"\E239"}.glyphicon-sunglasses:before{content:"\E240"}.glyphicon-text-size:before{content:"\E241"}.glyphicon-text-color:before{content:"\E242"}.glyphicon-text-background:before{content:"\E243"}.glyphicon-object-align-top:before{content:"\E244"}.glyphicon-object-align-bottom:before{content:"\E245"}.glyphicon-object-align-horizontal:before{content:"\E246"}.glyphicon-object-align-left:before{content:"\E247"}.glyphicon-object-align-vertical:before{content:"\E248"}.glyphicon-object-align-right:before{content:"\E249"}.glyphicon-triangle-right:before{content:"\E250"}.glyphicon-triangle-left:before{content:"\E251"}.glyphicon-triangle-bottom:before{content:"\E252"}.glyphicon-triangle-top:before{content:"\E253"}.glyphicon-console:before{content:"\E254"}.glyphicon-superscript:before{content:"\E255"}.glyphicon-subscript:before{content:"\E256"}.glyphicon-menu-left:before{content:"\E257"}.glyphicon-menu-right:before{content:"\E258"}.glyphicon-menu-down:before{content:"\E259"}.glyphicon-menu-up:before{content:"\E260"}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:"\2014 \A0"}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:""}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:"\A0 \2014"}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Courier New,monospace}code{color:#c7254e;background-color:#f9f2f4;border-radius:4px}code,kbd{padding:2px 4px;font-size:90%}kbd{color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777}caption,th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{margin:0;min-width:0}fieldset,legend{padding:0;border:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{padding-top:7px}.form-control,output{display:block;font-size:14px;line-height:1.42857143;color:#555}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-transition:border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-box-shadow .15s ease-in-out}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=datetime-local],input[type=month],input[type=time]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox-inline input[type=checkbox],.checkbox input[type=checkbox],.radio-inline input[type=radio],.radio input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .checkbox label,fieldset[disabled] .radio-inline,fieldset[disabled] .radio label,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success.checkbox-inline label,.has-success.checkbox label,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.radio-inline label,.has-success.radio label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning.checkbox-inline label,.has-warning.checkbox label,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.radio-inline label,.has-warning.radio label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error.checkbox-inline label,.has-error.checkbox label,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.radio-inline label,.has-error.radio label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.333333px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:400;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group .form-control:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group .form-control:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li,.nav>li>a{position:relative;display:block}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1);box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;visibility:visible!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container-fluid .navbar-brand,.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{margin:8px -15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1),0 1px 0 hsla(0,0%,100%,.1);box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1),0 1px 0 hsla(0,0%,100%,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\A0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#337ab7;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;background-color:#eee}.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container-fluid .jumbotron,.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container-fluid .jumbotron,.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{0%{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{0%{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#777;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle,.panel-title{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table-responsive>.table caption,.panel>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-transition:-webkit-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0);transform:translate(0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;visibility:visible;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel,.carousel-inner{position:relative}.carousel-inner{overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:left .6s ease-in-out;transition:left .6s ease-in-out}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media (-webkit-transform-3d),(transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translateZ(0);transform:translateZ(0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(90deg,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001));background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#80000000",endColorstr="#00000000",GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(90deg,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5));background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#00000000",endColorstr="#80000000",GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203A"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000\9;background-color:transparent}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:" ";display:table}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.ekko-lightbox{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-right:0!important}.ekko-lightbox-container{position:relative}.ekko-lightbox-container>div.ekko-lightbox-item{position:absolute;top:0;left:0;bottom:0;right:0;width:100%}.ekko-lightbox iframe{width:100%;height:100%}.ekko-lightbox-nav-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ekko-lightbox-nav-overlay,.ekko-lightbox-nav-overlay a{z-index:100;display:-webkit-box;display:-ms-flexbox;display:flex}.ekko-lightbox-nav-overlay a{-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center;opacity:0;-webkit-transition:opacity .5s;transition:opacity .5s;color:#fff;font-size:30px}.ekko-lightbox-nav-overlay a>*{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.ekko-lightbox-nav-overlay a>:focus{outline:none}.ekko-lightbox-nav-overlay a span{padding:0 30px}.ekko-lightbox-nav-overlay a:last-child span{text-align:right}.ekko-lightbox-nav-overlay a:hover{text-decoration:none}.ekko-lightbox-nav-overlay a:focus{outline:none}.ekko-lightbox-nav-overlay a.disabled{cursor:default;visibility:hidden}.ekko-lightbox a:hover{opacity:1;text-decoration:none}.ekko-lightbox .modal-dialog{display:none}.ekko-lightbox .modal-footer{text-align:left}.ekko-lightbox-loader{position:absolute;top:0;left:0;bottom:0;right:0;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.ekko-lightbox-loader>div{width:40px;height:40px;position:relative;text-align:center}.ekko-lightbox-loader>div>div{width:100%;height:100%;border-radius:50%;background-color:#fff;opacity:.6;position:absolute;top:0;left:0;-webkit-animation:sk-bounce 2s infinite ease-in-out;animation:sk-bounce 2s infinite ease-in-out}.ekko-lightbox-loader>div>div:last-child{-webkit-animation-delay:-1s;animation-delay:-1s}.modal-dialog .ekko-lightbox-loader>div>div{background-color:#333}@-webkit-keyframes sk-bounce{0%,to{-webkit-transform:scale(0)}50%{-webkit-transform:scale(1)}}@keyframes sk-bounce{0%,to{transform:scale(0);-webkit-transform:scale(0)}50%{transform:scale(1);-webkit-transform:scale(1)}}/*! - * Bootstrap Colorpicker v2.5.2 - * https://itsjavi.com/bootstrap-colorpicker/ - * - * Originally written by (c) 2012 Stefan Petre - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0.txt - * - */.colorpicker-saturation{width:100px;height:100px;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAQAAADa613fAAAP9klEQVR4XnRWC47rNgwcKjlA0bv2VL1Qi/YELRav7203iS1ppqZoiXCAhuBHVLI74xFtG3/Hz2joIOjRGuR5eMYuRn9YA1fds859KX8ZvczLr9/pImiR3Rqky9/wlajRIdVE/1Rufeu/0No3/ASgBZAJUkwgi0iCaEatekJJoEqiTQncd67/gyOfRCZshTed0Nl8LbLj8D6qxtoq9/7kJz/aH/3Xfu8VwI5+AUH8DxE7gUyiIpZ5LwiGzUqE3CScJsCDQHAsvBnxWpkbC0QMHmBp6latWS0bnvrCN/x1+xPfce+Ij0GAyeAGGz15sOiax2UylPhKrFaMPnVWClwepKh07hdhkVDsK2uoyEIySergjdbY2VBtV8VLr8Mf9mF/4wMb7kR8FOhzFWZZe7HIZD9JRIbee28eJKBweTB6TwjYkAgWaUmtDveGw1Wx3zZ76YlPPfQd/+gTTUFkiGiJ+NQAszU1EPT/QJEgufolAMPkNU4CVOyUIBLg4xglEZHGQnTFOFV0VaulYddBhA986ge/7N/yQi/3flFgwfQq2ibLnTDBRl9TmUHyJASPV/eoN0UISIr+ICQKIFV4EpljSjV1uFVUq9hRtet5e9gXvuyHPW0zMhQxWaoBBa9Tg8vsCEhww23Smd0CKjIkmPIoxWrUBDgJqFCyESF43ctQxLUoHN7Q1KyVhqrNNm3cy2vMyQNPVKjc29Rh5SSU+giWdRJHkLnQG71FQEuNyNGBTDdBQQAKCuGiEUS/jcyGbkMPq931OIzb/dUPGuVlG7f+slqkO5NAAlzTMdcq0NkzmsEBmAQkbI+pSHbiqnuWIA6lijhvqwIxMyWxMGZiPU669XJE1tADDTs2HWpwKxuqdnTpOiOR42xlzLtm3pXGel3xd8/oTs8Xy0MV8GM1RlsC2Y3Wy3wut3M+2mEVux0Gt9fhzTWyLvGiiJYaqY5DWRFIwAiQ5r6gB9GpQihJw4I9j5Mkscj3BnzGjBhv8xna5P1Jo428o6IOPY5KFZtVOkEKqUjqQY9Gi+jrIOFwJUDzRtA9xyoIrGGmkNRmxVAnZoK+TkUIeUYni5wEzgOG5iZX5HCr2JyQNqdk++G0rgb1ochSIGutTj4P7F0PuRUAolmh5sCzAHn1BYyaADh6bgFeoBx6vst091CEvcSLWBBpqGq384jZ5llVHSwEShLx+D4d0mU3D5eEAJQ9KEhOZUYnDENV2qKgmIlQhWfdvcoXYaegPp/n1oKIOgYFqxrzQSciqNhv/5FqPpy6b0UcX2vf13DfWySRSEgkEYlEJJGQSyKJSEQSCYlEEpHexIVO3XOevffze2a+PfPv9x1rne1c3b3Mmlmz9mE++zuzngfnw/E+Dlc4LL4NwHdFy7u3KGPVmZ6/4eeMoDyre3i/KHADIHYO04w9zO0mAotuKnrc7XaPjvu66bNe5cDT7RlPepEnfS2X8dF1/utDvD+OwGDBxEgQywLCvIMYWBY+DShwAAORAdv9PswhDAqOUCi5+71AbFcDMR4xBDNfhySKXPXZ1+Vub+Q1Ltf5z7eC0AjVldHI26rIFdKIAyYBJCFVUhVDwttAnM52B3Ect1TFQXzJ0z33lOuib/QO8g+CuO0gKBRU80A8hkeJ0b1KRQWmFQVSh8mf3lpUpNaRulzN5NArrmKKGMijXgzk7w5ijdFVgT8f1IdFNjVWjDWicUYWEEMmSFDtILdzHW5XueHp7p+yuS54ep5/c5BE2Gw/gWPNYU4/PZaak2VGEsFjSbOf8irea6KQgojGCk0KxZY31tWWgzwayF8N5KYyo3VADVicWWrhwzr3ZqIOa5xW5zbqMPPMiyDURHDIHQTeWq7KFXcQPOqzPOL5Ov/iIDEDy7DHEwx0PTgjO8SS0fOEHcZNMt+XKEFMj8Q4QUSvPu6HPuvd4N9/x12RPwcIVRCAakSOUzHgsUSMFWYzDQ+PiOJqAOuYc9jh5TecnA+xHfFyOYhebeTH89P80wrCJzUjlsx7euIV0g4zQFUSiBPioIWBACFC7GgDj8P91ZSJOQmQP74MAnQo8H5RIe8kZ0kBcQCMAlEpRDiKROBxbR0ksdhWFq0gR9q9uQzkDzuIFQSPqAgRCAsCaVNF2ZAAhxvtzcqcnDk6tpXxSsayqXLIgSOb6zqeH+fvO0i9XEu5EVV+OZehRZJ6BGTeaRhCkTzVIZeAzaWGAFfErIPogQI5CuR3HQQx7DzBB16R3s7e0MBUPedjWutgG/JUTPqMeAQNEiytJRnJearWUgdwFNxN7rtBoECuj/O3BMHaTIxQ0a4GctireElTJHJvLTaalih5kvBCGMvkdESUMAdCFaI4yG8SpDfRWAptqkAJUwCG6B7lOREFSZBqKs57MEHqVJEBwHa2lp0OiKtiQ18gx9P89QrSXyc0vObBM4vPmBADqJZLAo/yzK7qPSZstCy+fDSZlhrm+Zkyjsf5q2otdC14zkLjHLf0me9wjNqQo0B1a6wBJRaIEgC2Qw9oby/cRHA+xHCQy/xlB1HVSV3Y/5yVhsc7dBi2UoIWCMcbELZWgxNCGUZ5y4ceBaLlE8dAfrEosrYT+z8ya3sxXndFBxuQivNGEHFCbLGBlBLKGYHZoeoQpcjtMn/uICPefcxecpuDOEemg9S/44cflZPIlWolyHkLrEpgbS9IQRlAgZgi0WDjsEiPh+PN/Fkogq4GdzPtarlRGW2tJwEK1RMTEvdVdmhAKHO1pdUuGQsVcX+rSfGzDbwGyE8NRPQc83HCaOkTZwPqABZBdFq8zAN1gue0FPO8wYUFBE1WkMwVzM1iQ4BItFh+H36Qy/yJg0DRQICmBl+tbKUC5cCj3yXI+SUFBS78ZAcBtHt+e9lBuiqpTNh9zTvIjzuIWxVYGQJpAZY+VWS3QKh84iSZbwuIdiDpc4KztQa/sjhMaDJEJDSZ8mZ+kCBdC0JpKVNQzZdKu+EsOeFCosrngVAkDS/uy6iGnW7UxmMpkB8FyFKo6iQW8z1HuBdMu1pdkZdB8jWTjlFtNaiJRYniIDcD+eECMqFLS9ED6DgxzCMKnRD3HYYA2uMCJUh70OK8G0EUnJV8lqe8nj84QdqLhdoJskNlEw1ivajM8LtPBhIeN99LESXI9xcQIHFQudHngZjUhXOQeGlUYmAddh5pxMhzV0M1vMAtMFIVmfp6fq+DgEWefjQVenstaqUy3bJQAiVlEihDghCDINFQg8oUhoQPkO8SBEM7SFQ72VYBwPuE7k8uYF5LNwg/TEd2zkuKjIIhTiJRlYrDfNS1QL7DYUcbcCyKJNwOwucVCVSwBBj/DwghXA2hQtACgCBBPprfXkAIFIYRXhONQARFU00Tsh6LEmmQUbkTImMi9me5qaHDIeBgHeRbdxAIqAJBCDSoCNVQglrciqX/ZCD9RRP6rgpBvhmKAFhg2ForBLXBYPtUjj7vCHPe8SXbYAY47gHB9mKeqjjIg/53fmMD0fR9Bug7SFcHI6EA1OC/E8QTL4NgBSGiCiyTChnI1zcQxmyfRZGM6w701KRybDvsIK3LWDx6mxGkcglEZQLkawnCdppZ6sgCh8trWWBUQaUWCEOlOs7HAenFE45QSu9RQQDAqchXNxDq4orQR44qRIFUQvM+mRJuB6GDEixgCbSBQGXghEEbdn1P/zO/QhAWCsWsmRhLa2VFkSZIgSVKmgEQhvk6K8YKMRZl7Dwg4amOUYvFBfLlE4RasOCB5S9PXKq0AqGDMiYIReXF0mYctITWBmqR5F38X5Y7yJfeCtKBzNbWYm5XpsMpf3dRZD3jPDesvdVCOs6KYQXIFw1E4fcE8dHWOepZBXpLJcACWUZVMRZbfvgXR4Ak8A7VVSKSVuu9p6/mFxyE7cOWavtLp952O8huK83+gmHzHaAsVXLgAvl8gPCvHzAFsM8GNXGKPH5cmN02sXTLa8QdKRXMzHv67/k5A9k1UIx36UH/VlWWtuKssNiRapB6BaLXl6MA+ayDcNS3v/sYXgCL620F1kk8QhKAEOvKu4DvajDO5zkHc4fBg76anyEIIcamBPex5EK8AoVHhMW7QAqWrYD1204CJB1hCfOAV/PTBPH0zBmJmsZZKCEaAmdqm4zMcYxYLN0JuHThIAjirAnp3px7TRgD+ZSD/K92M1CNIgbC8Ex7FkSEIlQEEUQEQQQBRBABEUQQEQTx3X0Evap9AhP39jL5OvuzAWuvbDaTTDIzX2aypUCJ0i7nAigoQAk9gUIUSxXEoCFyyVIuL9ZQcMZoArnwr4D0OLS8jGNGTgGnsZQWMYrcOARoIReAALBeWhf+RUCAIEsECFQHLkwR5zj4JW3t5WOUU5djvgQIawD53EDsctmYz8xGaZGPBUR3qNkiGwqDICUYIFpqBgRaayCfFiAWR2wWvoobmzxdF8N5kyxXmvap/sgGcLF/aoBosbG+lE395R8zCA4BqUYgOgYq+HtvBrT0LK15X8lZwx5f9klCX0rdgXzIIGbdhXMqZtHzJhuptEjmsFc4KzmN5IFPtfM7gWw2kPczSIqQSPUDYKYBMamsBCpKphW0iA5H8AbMDPJOQYjLZg1Vk4G49GlCYNYAkdOd0kwRQ8FCyAHydgLZ6Z2AqrVtjDUQ7hCEmrkEooDAsB2YnBCvkBpZ6yBvJpCd7Mn5zJ6C4QF2BUQPgHEIGUrGnHzQ8rlMekBeTyAzwDJksxwM4+w3BY02B8mIl0CmFRm+ZscxAuSnvwqQsECTIGSV6FEoJFTygVuzB5xAsKqBvAQE3+nkVoJDI1BJIaPBWik7ZSu5NIp5A3mRQaTFvLgkO9fVgEgMqqeVfb+p55tijWH+Kea71ubq4v8Sl8089sZKbKEZNq+VUfISJJF7j79WrbYgS994ZEf+nIz0pNFRWqapSmK6P45i3OQuItIiPDyg6RnxZ4D0g+CFPxAzluoRsWsaA6I6JOqVWCisDvJ0BgHTzMSRgMi0vmi8R+sR6tg/XUh7kCc7kMRqSNkTBDx0OkAUegFcMazciBXNpm798R6klXap/WZz49TQwBHqEcj4oCToUPjUuP9lfxcbyKMAwT6bTf1qqIIQDl3i5oCERNmVm0wgW4A8BGRxMX3hWh8bEV5Rvfp4DS5F3djWH2ztDNWKW7OBjgjIwsDWaKRknJjqMsh9QCa1p608lLovFkBE969DYtYelSzwSRcg535vAsFeNU9SzRCYZb4LDmxmFQKkwYGM+5y/G7b1uxMIylLdyE5yxIyYsoXWhQIpzQhYPi3JkJoKkB9+BxD0OMuyOEBe36DgyPSrxscmATldgKj8PxrkA/kA5PYMgkrocwIQ6GSRGmF0VaNqBKQZ5FYDEZSDzFTzq9mBQjAayE1A+ryDTzcQZe0Ibbxj7EwpAmTrJwEimZR9CCPtODhzxuNtY19Zd2Lf/fjCTnEiDAOg62j1utb/dv9mZ/aHCj4AyOHbsW3/As0BTzIgeJU7AAAAAElFTkSuQmCC");cursor:crosshair;float:left}.colorpicker-saturation i{display:block;height:5px;width:5px;border:1px solid #000;border-radius:5px;position:absolute;top:0;left:0;margin:-4px 0 0 -4px}.colorpicker-saturation i b{display:block;height:5px;width:5px;border:1px solid #fff;border-radius:5px}.colorpicker-alpha,.colorpicker-hue{width:15px;height:100px;float:left;cursor:row-resize;margin-left:4px;margin-bottom:4px}.colorpicker-alpha i,.colorpicker-hue i{display:block;height:1px;background:#000;border-top:1px solid #fff;position:absolute;top:0;left:0;width:100%;margin-top:-1px}.colorpicker-hue{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAMAAABw8qpSAAABLFBMVEXqFBb/ABH/ACL/ADH/AEH/AFD/AGD/AG7/AH7/AI3/AJ3/AKz/ALz/AMr/ANv/AOr/APr2AP/mAP/XAP/HAP+4AP+oAP+aAP+JAP97AP9rAP9cAP9MAP8+AP8tAP8fAP8PAP8BAv8AEP8AH/8AL/8APv8ATv8AXP8Abf8Ae/8Ai/8Amv8Aqv8AuP8Ayf8A1/8A5/8A9/8A//gA/+kA/9kA/8oA/7oA/6wA/5sA/40A/30A/24A/14A/1AA/z8A/zEA/yEA/xEB/wMN/wAd/wAs/wA8/wBK/wBb/wBp/wB5/wCI/wCY/wCm/wC3/wDF/wDV/wDk/wD1/wD/+gD/7AD/3AD/zAD/vgD/rQD/nwD/jgD/gAD/cAD/YgD/UQD/QwD/MgD/JAD/FAD4Eg42qAedAAAAh0lEQVR4XgXAg3EDAAAAwI9to7Zt27a1/w49BASFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHXo1KVbj159+g0YNGTYiFFjxk2YNGXajFlz5i1YtGTZilVr1m3YtGXbjl179h04dOTYiVNnzl24dOXajVt37j149OTZi1dv3n349OXbj19//wOxE1dQ8reGAAAAAElFTkSuQmCC")}.colorpicker-alpha{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAABkCAQAAAAVxWkcAAABr0lEQVR4Xo2VwU0DQQxF7dmRuNIFlzlSAR3QAaXQQdIBJVABFXDcOVAAd67cjJLR07dkhcSrkZKfb/t7bG88rFo3B5gZPMNycItu2xloGV7MWHzM9zuzFWCkmA0nK6AszCUJDW6+mG6R03ncw5v8EMTEvZ2O3AliYjpslblc0RF9LmZYWxURU6aKytWZYsoWCAe+xwOZp1GsEukGiIkYxcQCHck99+gRgB7JncyIB5SGEhP3Yh5P6JwX+u6AnYot104d8DJT7uH7M9JH6OZbimj0vfMVaYnJIZFJDBW9kHlerL2C6JV4mSt7uuo2N57RxnZ+usQjn0R1jwBJBrNO3evJpVYUWsJ/E3UiXRlv24/7YZ04xmEdWlzcKS+B/eapeyMvFd2k0+hRk/T0AmTW8h69s2sjYMsdPntECiILhAeIMZAeH4QvUwfn6ijC0tTV+fT9ky8jM9nK2g7Ly1VjSpKYq6IvsAm7MtNu1orEqa/K3KNvgMFdhfquPfJmp2dbh0/8Gzb6Y22ViaNr6n5410zXdngVhbu6XqdOtWOuin5hjABGp4a2uotZ71MVCfwDBt2/v37yo6AAAAAASUVORK5CYII=");display:none}.colorpicker-alpha,.colorpicker-hue,.colorpicker-saturation{background-size:contain}.colorpicker{padding:4px;min-width:130px;margin-top:1px;border-radius:4px;z-index:2500}.colorpicker:after,.colorpicker:before{display:table;content:"";line-height:0}.colorpicker:after{clear:both}.colorpicker:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);top:-7px;left:6px}.colorpicker:after,.colorpicker:before{content:"";display:inline-block;position:absolute}.colorpicker:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;top:-6px;left:7px}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAABkCAQAAAAVxWkcAAABr0lEQVR4Xo2VwU0DQQxF7dmRuNIFlzlSAR3QAaXQQdIBJVABFXDcOVAAd67cjJLR07dkhcSrkZKfb/t7bG88rFo3B5gZPMNycItu2xloGV7MWHzM9zuzFWCkmA0nK6AszCUJDW6+mG6R03ncw5v8EMTEvZ2O3AliYjpslblc0RF9LmZYWxURU6aKytWZYsoWCAe+xwOZp1GsEukGiIkYxcQCHck99+gRgB7JncyIB5SGEhP3Yh5P6JwX+u6AnYot104d8DJT7uH7M9JH6OZbimj0vfMVaYnJIZFJDBW9kHlerL2C6JV4mSt7uuo2N57RxnZ+usQjn0R1jwBJBrNO3evJpVYUWsJ/E3UiXRlv24/7YZ04xmEdWlzcKS+B/eapeyMvFd2k0+hRk/T0AmTW8h69s2sjYMsdPntECiILhAeIMZAeH4QvUwfn6ijC0tTV+fT9ky8jM9nK2g7Ly1VjSpKYq6IvsAm7MtNu1orEqa/K3KNvgMFdhfquPfJmp2dbh0/8Gzb6Y22ViaNr6n5410zXdngVhbu6XqdOtWOuin5hjABGp4a2uotZ71MVCfwDBt2/v37yo6AAAAAASUVORK5CYII=");background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-selectors{display:none;height:10px;margin-top:5px;clear:both}.colorpicker-selectors i{cursor:pointer;float:left;height:10px;width:10px}.colorpicker-selectors i+i{margin-left:3px}.colorpicker-element .add-on i,.colorpicker-element .input-group-addon i{display:inline-block;cursor:pointer;height:16px;vertical-align:text-top;width:16px}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none;z-index:auto}.colorpicker.colorpicker-horizontal{width:110px;min-width:110px;height:auto}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-alpha,.colorpicker.colorpicker-horizontal .colorpicker-hue{width:100px;height:15px;float:left;cursor:col-resize;margin-left:0;margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-alpha i,.colorpicker.colorpicker-horizontal .colorpicker-hue i{display:block;height:15px;background:#fff;position:absolute;top:0;left:0;width:1px;border:none;margin-top:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAABCAMAAAAfBfuPAAABLFBMVEXqFBb/ABH/ACL/ADH/AEH/AFD/AGD/AG7/AH7/AI3/AJ3/AKz/ALz/AMr/ANv/AOr/APr2AP/mAP/XAP/HAP+4AP+oAP+aAP+JAP97AP9rAP9cAP9MAP8+AP8tAP8fAP8PAP8BAv8AEP8AH/8AL/8APv8ATv8AXP8Abf8Ae/8Ai/8Amv8Aqv8AuP8Ayf8A1/8A5/8A9/8A//gA/+kA/9kA/8oA/7oA/6wA/5sA/40A/30A/24A/14A/1AA/z8A/zEA/yEA/xEB/wMN/wAd/wAs/wA8/wBK/wBb/wBp/wB5/wCI/wCY/wCm/wC3/wDF/wDV/wDk/wD1/wD/+gD/7AD/3AD/zAD/vgD/rQD/nwD/jgD/gAD/cAD/YgD/UQD/QwD/MgD/JAD/FAD4Eg42qAedAAAAbUlEQVR4XgXAghEDsbxtlrZt27ax/w49ACAYQTGcICmaYTleECVZUTXdMC1Wm93hdLk9Xp8/EAyFI9FYPJFMpTPZXL5QLJUr1Vq90Wy1O91efzAcjSfT2XyxXK03293+cDydL9fb/fF8vT/f3x+LfRNXARMbCAAAAABJRU5ErkJggg==")}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAKCAQAAADoFTP1AAAB9ElEQVR4XoWTQW4VMRBEu9qWEimL7DhEMp8NF+ASnJJLcAQgE1bcgBUSkYKUuHCrZ9pjeqSU5Yn9LPu7umJQBIIv+k7vIOrtK66L4lmr3pVOrOv3otp619KZ0/KjdNI79L52Uo09FBQWrU0vfe5trezU+hLsoUKd3Repovte+0vbq/7Lj5XbaHECKasR9G4MPlbp+gzZxd6koPEJCkAYC5SjcOTAIIOK90Dja1IfIZ8Z+zAY9jm3b5Ia+MT5sFcqRJrR2AYYA8Kua5BzYRrFPNmD4PQMegGJMOffJJUsWiI3nCHZZjInNdffLWOufzbc3JaboCAVxwmnRHbhLSPwRJ4wU0BRSc6HkECYYVw95nMKgJOcylxrJttE5Ibzf9Xq9GPvP+WX3MiV/MGHfRu/SentRQrfG1GzsIrytdNXucSRKxQNIGHM9YhGFQJcdjNcBZvfJayuYe4Sia1CzwW+19mWOhe37HsxJWKwbu/jluEU15QzAQjAqCEbhMJc78GYV2E0kooHDubUImWkTOhGpgv8PoT8DJG/bzxna4BZ0eOFSOaLADGeSpFsg5AzeaDZIDQQXjZ4y/8ryfzUXBwdELRjTjCNvOeT0rNlrJz90vwy6N9pXXQEluX0inElpPWokSdiLCfiNJJjMKQ8Qsh8GEKQKMo/eiHrNbI9UksAAAAASUVORK5CYII=")}.colorpicker-right:before{left:auto;right:6px}.colorpicker-right:after{left:auto;right:7px}.colorpicker-no-arrow:after,.colorpicker-no-arrow:before{border-right:0;border-left:0}.colorpicker-alpha.colorpicker-visible,.colorpicker-hue.colorpicker-visible,.colorpicker-saturation.colorpicker-visible,.colorpicker-selectors.colorpicker-visible,.colorpicker.colorpicker-visible{display:block}.colorpicker-alpha.colorpicker-hidden,.colorpicker-hue.colorpicker-hidden,.colorpicker-saturation.colorpicker-hidden,.colorpicker-selectors.colorpicker-hidden,.colorpicker.colorpicker-hidden{display:none}.colorpicker-inline.colorpicker-visible{display:inline-block} -/*# sourceMappingURL=app.css.map*/ \ No newline at end of file diff --git a/public/css/bootstrap-table.css b/resources/assets/css/bootstrap-table.css similarity index 100% rename from public/css/bootstrap-table.css rename to resources/assets/css/bootstrap-table.css diff --git a/public/css/bootstrap-tables-sticky-header.css b/resources/assets/css/bootstrap-tables-sticky-header.css similarity index 100% rename from public/css/bootstrap-tables-sticky-header.css rename to resources/assets/css/bootstrap-tables-sticky-header.css diff --git a/public/css/bootstrap.css b/resources/assets/css/bootstrap.css similarity index 100% rename from public/css/bootstrap.css rename to resources/assets/css/bootstrap.css diff --git a/public/css/bootstrap.css.map b/resources/assets/css/bootstrap.css.map similarity index 100% rename from public/css/bootstrap.css.map rename to resources/assets/css/bootstrap.css.map diff --git a/public/css/bootstrap.datepicker.css b/resources/assets/css/bootstrap.datepicker.css similarity index 100% rename from public/css/bootstrap.datepicker.css rename to resources/assets/css/bootstrap.datepicker.css diff --git a/public/css/bootstrap.min.css b/resources/assets/css/bootstrap.min.css similarity index 100% rename from public/css/bootstrap.min.css rename to resources/assets/css/bootstrap.min.css diff --git a/resources/assets/css/fonts/FontAwesome.otf b/resources/assets/css/fonts/FontAwesome.otf new file mode 100644 index 0000000000..401ec0f36e Binary files /dev/null and b/resources/assets/css/fonts/FontAwesome.otf differ diff --git a/resources/assets/css/fonts/fontawesome-webfont.eot b/resources/assets/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000..e9f60ca953 Binary files /dev/null and b/resources/assets/css/fonts/fontawesome-webfont.eot differ diff --git a/resources/assets/css/fonts/fontawesome-webfont.svg b/resources/assets/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000..855c845e53 --- /dev/null +++ b/resources/assets/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/assets/css/fonts/fontawesome-webfont.ttf b/resources/assets/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000..35acda2fa1 Binary files /dev/null and b/resources/assets/css/fonts/fontawesome-webfont.ttf differ diff --git a/resources/assets/css/fonts/fontawesome-webfont.woff b/resources/assets/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000..400014a4b0 Binary files /dev/null and b/resources/assets/css/fonts/fontawesome-webfont.woff differ diff --git a/resources/assets/css/fonts/fontawesome-webfont.woff2 b/resources/assets/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000..4d13fc6040 Binary files /dev/null and b/resources/assets/css/fonts/fontawesome-webfont.woff2 differ diff --git a/public/css/lib/bootstrap-wysihtml5.css b/resources/assets/css/lib/bootstrap-wysihtml5.css similarity index 100% rename from public/css/lib/bootstrap-wysihtml5.css rename to resources/assets/css/lib/bootstrap-wysihtml5.css diff --git a/public/css/lib/bootstrap.datepicker.css b/resources/assets/css/lib/bootstrap.datepicker.css similarity index 100% rename from public/css/lib/bootstrap.datepicker.css rename to resources/assets/css/lib/bootstrap.datepicker.css diff --git a/public/css/lib/dragtable.css b/resources/assets/css/lib/dragtable.css similarity index 100% rename from public/css/lib/dragtable.css rename to resources/assets/css/lib/dragtable.css diff --git a/public/css/lib/font-awesome.css b/resources/assets/css/lib/font-awesome.css similarity index 100% rename from public/css/lib/font-awesome.css rename to resources/assets/css/lib/font-awesome.css diff --git a/public/css/lib/font-awesome.min.css b/resources/assets/css/lib/font-awesome.min.css similarity index 100% rename from public/css/lib/font-awesome.min.css rename to resources/assets/css/lib/font-awesome.min.css diff --git a/public/css/lib/fullcalendar.css b/resources/assets/css/lib/fullcalendar.css similarity index 100% rename from public/css/lib/fullcalendar.css rename to resources/assets/css/lib/fullcalendar.css diff --git a/public/css/lib/fullcalendar.print.css b/resources/assets/css/lib/fullcalendar.print.css similarity index 100% rename from public/css/lib/fullcalendar.print.css rename to resources/assets/css/lib/fullcalendar.print.css diff --git a/public/css/lib/jquery-ui-1.10.2.custom.css b/resources/assets/css/lib/jquery-ui-1.10.2.custom.css similarity index 100% rename from public/css/lib/jquery-ui-1.10.2.custom.css rename to resources/assets/css/lib/jquery-ui-1.10.2.custom.css diff --git a/public/css/lib/jquery.dataTables.css b/resources/assets/css/lib/jquery.dataTables.css similarity index 100% rename from public/css/lib/jquery.dataTables.css rename to resources/assets/css/lib/jquery.dataTables.css diff --git a/public/css/lib/jquery.fileupload-ui.css b/resources/assets/css/lib/jquery.fileupload-ui.css similarity index 100% rename from public/css/lib/jquery.fileupload-ui.css rename to resources/assets/css/lib/jquery.fileupload-ui.css diff --git a/public/css/lib/jquery.fileupload.css b/resources/assets/css/lib/jquery.fileupload.css similarity index 100% rename from public/css/lib/jquery.fileupload.css rename to resources/assets/css/lib/jquery.fileupload.css diff --git a/public/css/lib/morris.css b/resources/assets/css/lib/morris.css similarity index 100% rename from public/css/lib/morris.css rename to resources/assets/css/lib/morris.css diff --git a/public/css/select2.css b/resources/assets/css/lib/select2.css similarity index 91% rename from public/css/select2.css rename to resources/assets/css/lib/select2.css index ae46ec3b42..fb6be4b6d8 100755 Binary files a/public/css/select2.css and b/resources/assets/css/lib/select2.css differ diff --git a/public/css/lib/select2x2.png b/resources/assets/css/lib/select2x2.png similarity index 100% rename from public/css/lib/select2x2.png rename to resources/assets/css/lib/select2x2.png diff --git a/public/css/lib/uniform.default.css b/resources/assets/css/lib/uniform.default.css similarity index 100% rename from public/css/lib/uniform.default.css rename to resources/assets/css/lib/uniform.default.css diff --git a/resources/assets/css/signature-pad.css b/resources/assets/css/signature-pad.css new file mode 100755 index 0000000000..218b9c2365 --- /dev/null +++ b/resources/assets/css/signature-pad.css @@ -0,0 +1,135 @@ + +#signature-pad { + padding-top: 250px; + margin: auto; +} +.m-signature-pad { + + position: relative; + font-size: 10px; + width: 100%; + height: 300px; + border: 1px solid #e8e8e8; + background-color: #fff; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset; + border-radius: 4px; +} + +.m-signature-pad:before, .m-signature-pad:after { + position: absolute; + z-index: -1; + content: ""; + width: 40%; + height: 10px; + left: 20px; + bottom: 10px; + background: transparent; + -webkit-transform: skew(-3deg) rotate(-3deg); + -moz-transform: skew(-3deg) rotate(-3deg); + -ms-transform: skew(-3deg) rotate(-3deg); + -o-transform: skew(-3deg) rotate(-3deg); + transform: skew(-3deg) rotate(-3deg); + box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4); +} + +.m-signature-pad:after { + left: auto; + right: 20px; + -webkit-transform: skew(3deg) rotate(3deg); + -moz-transform: skew(3deg) rotate(3deg); + -ms-transform: skew(3deg) rotate(3deg); + -o-transform: skew(3deg) rotate(3deg); + transform: skew(3deg) rotate(3deg); +} + +.m-signature-pad--body { + position: absolute; + top: 20px; + bottom: 60px; + border: 1px solid #f4f4f4; + background-color: white; +} + +.m-signature-pad--body + canvas { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + border-radius: 4px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset; + } + +.m-signature-pad--footer { + position: absolute; + left: 20px; + right: 20px; + bottom: 20px; + height: 40px; +} + +.m-signature-pad--footer + .description { + color: #C3C3C3; + text-align: center; + font-size: 1.2em; + margin-top: 1.8em; + } + +.m-signature-pad--footer + .button { + position: absolute; + bottom: 0; + } + +.m-signature-pad--footer + .button.clear { + left: 0; + } + +.m-signature-pad--footer + .button.save { + right: 0; + } + +@media screen and (max-width: 1024px) { + .m-signature-pad { + top: 0; + left: 0; + right: 0; + bottom: 0; + width: auto; + height: auto; + min-width: 250px; + min-height: 140px; + margin: 5%; + } + +} + +@media screen and (min-device-width: 768px) and (max-device-width: 1024px) { + .m-signature-pad { + margin: 10%; + } +} + +@media screen and (max-height: 320px) { + .m-signature-pad--body { + left: 0; + right: 0; + top: 0; + bottom: 32px; + } + .m-signature-pad--footer { + left: 20px; + right: 20px; + bottom: 4px; + height: 28px; + } + .m-signature-pad--footer + .description { + font-size: 1em; + margin-top: 1em; + } +} diff --git a/resources/assets/js/FileSaver.min.js b/resources/assets/js/FileSaver.min.js new file mode 100644 index 0000000000..9a1e397f20 --- /dev/null +++ b/resources/assets/js/FileSaver.min.js @@ -0,0 +1,2 @@ +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ +var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})} diff --git a/resources/assets/js/bootstrap-table-locale-all.js b/resources/assets/js/bootstrap-table-locale-all.js new file mode 100755 index 0000000000..2e02e8cc43 --- /dev/null +++ b/resources/assets/js/bootstrap-table-locale-all.js @@ -0,0 +1,1657 @@ +/** + * Bootstrap Table Afrikaans translation + * Author: Phillip Kruger + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['af-ZA'] = { + formatLoadingMessage: function () { + return 'Besig om te laai, wag asseblief ...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rekords per bladsy'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Resultate ' + pageFrom + ' tot ' + pageTo + ' van ' + totalRows + ' rye'; + }, + formatSearch: function () { + return 'Soek'; + }, + formatNoMatches: function () { + return 'Geen rekords gevind nie'; + }, + formatPaginationSwitch: function () { + return 'Wys/verberg bladsy nummering'; + }, + formatRefresh: function () { + return 'Herlaai'; + }, + formatToggle: function () { + return 'Wissel'; + }, + formatColumns: function () { + return 'Kolomme'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['af-ZA']); + +})(jQuery); + +/** + * Bootstrap Table English translation + * Author: Zhixin Wen + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ar-SA'] = { + formatLoadingMessage: function () { + return 'جاري التحميل, يرجى الإنتظار...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' سجل لكل صفحة'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'الظاهر ' + pageFrom + ' إلى ' + pageTo + ' من ' + totalRows + ' سجل'; + }, + formatSearch: function () { + return 'بحث'; + }, + formatNoMatches: function () { + return 'لا توجد نتائج مطابقة للبحث'; + }, + formatPaginationSwitch: function () { + return 'إخفاء\إظهار ترقيم الصفحات'; + }, + formatRefresh: function () { + return 'تحديث'; + }, + formatToggle: function () { + return 'تغيير'; + }, + formatColumns: function () { + return 'أعمدة'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ar-SA']); + +})(jQuery); + +/** + * Bootstrap Table Catalan translation + * Authors: Marc Pina + * Claudi Martinez + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ca-ES'] = { + formatLoadingMessage: function () { + return 'Espereu, si us plau...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' resultats per pàgina'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrant de ' + pageFrom + ' fins ' + pageTo + ' - total ' + totalRows + ' resultats'; + }, + formatSearch: function () { + return 'Cerca'; + }, + formatNoMatches: function () { + return 'No s\'han trobat resultats'; + }, + formatPaginationSwitch: function () { + return 'Amaga/Mostra paginació'; + }, + formatRefresh: function () { + return 'Refresca'; + }, + formatToggle: function () { + return 'Alterna formatació'; + }, + formatColumns: function () { + return 'Columnes'; + }, + formatAllRows: function () { + return 'Tots'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ca-ES']); + +})(jQuery); + +/** + * Bootstrap Table Czech translation + * Author: Lukas Kral (monarcha@seznam.cz) + * Author: Jakub Svestka + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['cs-CZ'] = { + formatLoadingMessage: function () { + return 'Čekejte, prosím...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' položek na stránku'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Zobrazena ' + pageFrom + '. - ' + pageTo + '. položka z celkových ' + totalRows; + }, + formatSearch: function () { + return 'Vyhledávání'; + }, + formatNoMatches: function () { + return 'Nenalezena žádná vyhovující položka'; + }, + formatPaginationSwitch: function () { + return 'Skrýt/Zobrazit stránkování'; + }, + formatRefresh: function () { + return 'Aktualizovat'; + }, + formatToggle: function () { + return 'Přepni'; + }, + formatColumns: function () { + return 'Sloupce'; + }, + formatAllRows: function () { + return 'Vše'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['cs-CZ']); + +})(jQuery); + +/** + * Bootstrap Table danish translation + * Author: Your Name Jan Borup Coyle, github@coyle.dk + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['da-DK'] = { + formatLoadingMessage: function () { + return 'Indlæser, vent venligst...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' poster pr side'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Viser ' + pageFrom + ' til ' + pageTo + ' af ' + totalRows + ' rækker'; + }, + formatSearch: function () { + return 'Søg'; + }, + formatNoMatches: function () { + return 'Ingen poster fundet'; + }, + formatRefresh: function () { + return 'Opdater'; + }, + formatToggle: function () { + return 'Skift'; + }, + formatColumns: function () { + return 'Kolonner'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['da-DK']); + +})(jQuery); +/** +* Bootstrap Table German translation +* Author: Paul Mohr - Sopamo +*/ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['de-DE'] = { + formatLoadingMessage: function () { + return 'Lade, bitte warten...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' Einträge pro Seite'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Zeige ' + pageFrom + ' bis ' + pageTo + ' von ' + totalRows + ' Zeile' + ((totalRows > 1) ? "n" : ""); + }, + formatSearch: function () { + return 'Suchen'; + }, + formatNoMatches: function () { + return 'Keine passenden Ergebnisse gefunden'; + }, + formatRefresh: function () { + return 'Neu laden'; + }, + formatToggle: function () { + return 'Umschalten'; + }, + formatColumns: function () { + return 'Spalten'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['de-DE']); + +})(jQuery); + +/** + * Bootstrap Table Greek translation + * Author: giannisdallas + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['el-GR'] = { + formatLoadingMessage: function () { + return 'Φορτώνει, παρακαλώ περιμένετε...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' αποτελέσματα ανά σελίδα'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Εμφανίζονται από την ' + pageFrom + ' ως την ' + pageTo + ' από σύνολο ' + totalRows + ' σειρών'; + }, + formatSearch: function () { + return 'Αναζητήστε'; + }, + formatNoMatches: function () { + return 'Δεν βρέθηκαν αποτελέσματα'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['el-GR']); + +})(jQuery); + +/** + * Bootstrap Table English translation + * Author: Zhixin Wen + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['en-US'] = { + formatLoadingMessage: function () { + return 'Loading, please wait...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rows per page'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Showing ' + pageFrom + ' to ' + pageTo + ' of ' + totalRows + ' rows'; + }, + formatSearch: function () { + return 'Search'; + }, + formatNoMatches: function () { + return 'No matching records found'; + }, + formatPaginationSwitch: function () { + return 'Hide/Show pagination'; + }, + formatRefresh: function () { + return 'Refresh'; + }, + formatToggle: function () { + return 'Toggle'; + }, + formatColumns: function () { + return 'Columns'; + }, + formatAllRows: function () { + return 'All'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US']); + +})(jQuery); + +/** + * Bootstrap Table Spanish (Argentina) translation + * Author: Felix Vera (felix.vera@gmail.com) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-AR'] = { + formatLoadingMessage: function () { + return 'Cargando, espere por favor...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrando ' + pageFrom + ' a ' + pageTo + ' de ' + totalRows + ' filas'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se encontraron registros'; + }, + formatAllRows: function () { + return 'Todo'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-AR']); + +})(jQuery); +/** + * Bootstrap Table Spanish (Costa Rica) translation + * Author: Dennis Hernández (http://djhvscf.github.io/Blog/) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-CR'] = { + formatLoadingMessage: function () { + return 'Cargando, por favor espere...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrando de ' + pageFrom + ' a ' + pageTo + ' registros de ' + totalRows + ' registros en total'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se encontraron registros'; + }, + formatRefresh: function () { + return 'Refrescar'; + }, + formatToggle: function () { + return 'Alternar'; + }, + formatColumns: function () { + return 'Columnas'; + }, + formatAllRows: function () { + return 'Todo'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-CR']); + +})(jQuery); + +/** + * Bootstrap Table Spanish Spain translation + * Author: Marc Pina + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-ES'] = { + formatLoadingMessage: function () { + return 'Por favor espere...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' resultados por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrando desde ' + pageFrom + ' hasta ' + pageTo + ' - En total ' + totalRows + ' resultados'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se encontraron resultados'; + }, + formatPaginationSwitch: function () { + return 'Ocultar/Mostrar paginación'; + }, + formatRefresh: function () { + return 'Refrescar'; + }, + formatToggle: function () { + return 'Ocultar/Mostrar'; + }, + formatColumns: function () { + return 'Columnas'; + }, + formatAllRows: function () { + return 'Todos'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-ES']); + +})(jQuery); + +/** + * Bootstrap Table Spanish (México) translation (Obtenido de traducción de Argentina) + * Author: Felix Vera (felix.vera@gmail.com) + * Copiado: Mauricio Vera (mauricioa.vera@gmail.com) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-MX'] = { + formatLoadingMessage: function () { + return 'Cargando, espere por favor...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrando ' + pageFrom + ' a ' + pageTo + ' de ' + totalRows + ' filas'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se encontraron registros'; + }, + formatAllRows: function () { + return 'Todo'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-MX']); + +})(jQuery); + +/** + * Bootstrap Table Spanish (Nicaragua) translation + * Author: Dennis Hernández (http://djhvscf.github.io/Blog/) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-NI'] = { + formatLoadingMessage: function () { + return 'Cargando, por favor espere...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Mostrando de ' + pageFrom + ' a ' + pageTo + ' registros de ' + totalRows + ' registros en total'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se encontraron registros'; + }, + formatRefresh: function () { + return 'Refrescar'; + }, + formatToggle: function () { + return 'Alternar'; + }, + formatColumns: function () { + return 'Columnas'; + }, + formatAllRows: function () { + return 'Todo'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-NI']); + +})(jQuery); + +/** + * Bootstrap Table Spanish (España) translation + * Author: Antonio Pérez + */ + (function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['es-SP'] = { + formatLoadingMessage: function () { + return 'Cargando, por favor espera...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página.'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return pageFrom + ' - ' + pageTo + ' de ' + totalRows + ' registros.'; + }, + formatSearch: function () { + return 'Buscar'; + }, + formatNoMatches: function () { + return 'No se han encontrado registros.'; + }, + formatRefresh: function () { + return 'Actualizar'; + }, + formatToggle: function () { + return 'Alternar'; + }, + formatColumns: function () { + return 'Columnas'; + }, + formatAllRows: function () { + return 'Todo'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['es-SP']); + +})(jQuery); +/** + * Bootstrap Table Estonian translation + * Author: kristjan@logist.it> + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['et-EE'] = { + formatLoadingMessage: function () { + return 'Päring käib, palun oota...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rida lehe kohta'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Näitan tulemusi ' + pageFrom + ' kuni ' + pageTo + ' - kokku ' + totalRows + ' tulemust'; + }, + formatSearch: function () { + return 'Otsi'; + }, + formatNoMatches: function () { + return 'Päringu tingimustele ei vastanud ühtegi tulemust'; + }, + formatPaginationSwitch: function () { + return 'Näita/Peida lehtedeks jagamine'; + }, + formatRefresh: function () { + return 'Värskenda'; + }, + formatToggle: function () { + return 'Lülita'; + }, + formatColumns: function () { + return 'Veerud'; + }, + formatAllRows: function () { + return 'Kõik'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['et-EE']); + +})(jQuery); +/** + * Bootstrap Table Persian translation + * Author: MJ Vakili + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['fa-IR'] = { + formatLoadingMessage: function () { + return 'در حال بارگذاری, لطفا صبر کنید...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' رکورد در صفحه'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'نمایش ' + pageFrom + ' تا ' + pageTo + ' از ' + totalRows + ' ردیف'; + }, + formatSearch: function () { + return 'جستجو'; + }, + formatNoMatches: function () { + return 'رکوردی یافت نشد.'; + }, + formatPaginationSwitch: function () { + return 'نمایش/مخفی صفحه بندی'; + }, + formatRefresh: function () { + return 'به روز رسانی'; + }, + formatToggle: function () { + return 'تغییر نمایش'; + }, + formatColumns: function () { + return 'سطر ها'; + }, + formatAllRows: function () { + return 'همه'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['fa-IR']); + +})(jQuery); +/** + * Bootstrap Table French (Belgium) translation + * Author: Julien Bisconti (julien.bisconti@gmail.com) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['fr-BE'] = { + formatLoadingMessage: function () { + return 'Chargement en cours...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' entrées par page'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Affiche de' + pageFrom + ' à ' + pageTo + ' sur ' + totalRows + ' lignes'; + }, + formatSearch: function () { + return 'Recherche'; + }, + formatNoMatches: function () { + return 'Pas de fichiers trouvés'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['fr-BE']); + +})(jQuery); + +/** + * Bootstrap Table French (France) translation + * Author: Dennis Hernández (http://djhvscf.github.io/Blog/) + * Modification: Tidalf (https://github.com/TidalfFR) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['fr-FR'] = { + formatLoadingMessage: function () { + return 'Chargement en cours, patientez, s´il vous plaît ...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' lignes par page'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Affichage des lignes ' + pageFrom + ' à ' + pageTo + ' sur ' + totalRows + ' lignes au total'; + }, + formatSearch: function () { + return 'Rechercher'; + }, + formatNoMatches: function () { + return 'Aucun résultat trouvé'; + }, + formatRefresh: function () { + return 'Rafraîchir'; + }, + formatToggle: function () { + return 'Alterner'; + }, + formatColumns: function () { + return 'Colonnes'; + }, + formatAllRows: function () { + return 'Tous'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['fr-FR']); + +})(jQuery); + +/** + * Bootstrap Table Hebrew translation + * Author: legshooter + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['he-IL'] = { + formatLoadingMessage: function () { + return 'טוען, נא להמתין...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' שורות בעמוד'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'מציג ' + pageFrom + ' עד ' + pageTo + ' מ-' + totalRows + ' שורות'; + }, + formatSearch: function () { + return 'חיפוש'; + }, + formatNoMatches: function () { + return 'לא נמצאו רשומות תואמות'; + }, + formatPaginationSwitch: function () { + return 'הסתר/הצג מספור דפים'; + }, + formatRefresh: function () { + return 'רענן'; + }, + formatToggle: function () { + return 'החלף תצוגה'; + }, + formatColumns: function () { + return 'עמודות'; + }, + formatAllRows: function () { + return 'הכל'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['he-IL']); + +})(jQuery); + +/** + * Bootstrap Table Croatian translation + * Author: Petra Štrbenac (petra.strbenac@gmail.com) + * Author: Petra Štrbenac (petra.strbenac@gmail.com) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['hr-HR'] = { + formatLoadingMessage: function () { + return 'Molimo pričekajte ...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' broj zapisa po stranici'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Prikazujem ' + pageFrom + '. - ' + pageTo + '. od ukupnog broja zapisa ' + totalRows; + }, + formatSearch: function () { + return 'Pretraži'; + }, + formatNoMatches: function () { + return 'Nije pronađen niti jedan zapis'; + }, + formatPaginationSwitch: function () { + return 'Prikaži/sakrij stranice'; + }, + formatRefresh: function () { + return 'Osvježi'; + }, + formatToggle: function () { + return 'Promijeni prikaz'; + }, + formatColumns: function () { + return 'Kolone'; + }, + formatAllRows: function () { + return 'Sve'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['hr-HR']); + +})(jQuery); + +/** + * Bootstrap Table Hungarian translation + * Author: Nagy Gergely + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['hu-HU'] = { + formatLoadingMessage: function () { + return 'Betöltés, kérem várjon...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rekord per oldal'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Megjelenítve ' + pageFrom + ' - ' + pageTo + ' / ' + totalRows + ' összesen'; + }, + formatSearch: function () { + return 'Keresés'; + }, + formatNoMatches: function () { + return 'Nincs találat'; + }, + formatPaginationSwitch: function () { + return 'Lapozó elrejtése/megjelenítése'; + }, + formatRefresh: function () { + return 'Frissítés'; + }, + formatToggle: function () { + return 'Összecsuk/Kinyit'; + }, + formatColumns: function () { + return 'Oszlopok'; + }, + formatAllRows: function () { + return 'Összes'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['hu-HU']); + +})(jQuery); + +/** + * Bootstrap Table Italian translation + * Author: Davide Renzi + * Author: Davide Borsatto + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['it-IT'] = { + formatLoadingMessage: function () { + return 'Caricamento in corso...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' elementi per pagina'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Pagina ' + pageFrom + ' di ' + pageTo + ' (' + totalRows + ' records)'; + }, + formatSearch: function () { + return 'Cerca'; + }, + formatNoMatches: function () { + return 'Nessun elemento trovato'; + }, + formatRefresh: function () { + return 'Aggiorna'; + }, + formatToggle: function () { + return 'Alterna'; + }, + formatColumns: function () { + return 'Colonne'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['it-IT']); + +})(jQuery); + +/** + * Bootstrap Table Japanese translation + * Author: Azamshul Azizy + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ja-JP'] = { + formatLoadingMessage: function () { + return '読み込み中です。少々お待ちください。'; + }, + formatRecordsPerPage: function (pageNumber) { + return 'ページ当たり最大' + pageNumber + '件'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return '全' + totalRows + '件から、'+ pageFrom + 'から' + pageTo + '件目まで表示しています'; + }, + formatSearch: function () { + return '検索'; + }, + formatNoMatches: function () { + return '該当するレコードが見つかりません'; + }, + formatPaginationSwitch: function () { + return 'ページ数を表示・非表示'; + }, + formatRefresh: function () { + return '更新'; + }, + formatToggle: function () { + return 'トグル'; + }, + formatColumns: function () { + return '列'; + }, + formatAllRows: function () { + return 'すべて'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ja-JP']); + +})(jQuery); +/** + * Bootstrap Table Georgian translation + * Author: Levan Lotuashvili + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ka-GE'] = { + formatLoadingMessage: function() { + return 'იტვირთება, გთხოვთ მოიცადოთ...'; + }, + formatRecordsPerPage: function(pageNumber) { + return pageNumber + ' ჩანაწერი თითო გვერდზე'; + }, + formatShowingRows: function(pageFrom, pageTo, totalRows) { + return 'ნაჩვენებია ' + pageFrom + '-დან ' + pageTo + '-მდე ჩანაწერი ჯამური ' + totalRows + '-დან'; + }, + formatSearch: function() { + return 'ძებნა'; + }, + formatNoMatches: function() { + return 'მონაცემები არ არის'; + }, + formatPaginationSwitch: function() { + return 'გვერდების გადამრთველის დამალვა/გამოჩენა'; + }, + formatRefresh: function() { + return 'განახლება'; + }, + formatToggle: function() { + return 'ჩართვა/გამორთვა'; + }, + formatColumns: function() { + return 'სვეტები'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ka-GE']); + +})(jQuery); + +/** + * Bootstrap Table Korean translation + * Author: Yi Tae-Hyeong (jsonobject@gmail.com) + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ko-KR'] = { + formatLoadingMessage: function () { + return '데이터를 불러오는 중입니다...'; + }, + formatRecordsPerPage: function (pageNumber) { + return '페이지 당 ' + pageNumber + '개 데이터 출력'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return '전체 ' + totalRows + '개 중 ' + pageFrom + '~' + pageTo + '번째 데이터 출력,'; + }, + formatSearch: function () { + return '검색'; + }, + formatNoMatches: function () { + return '조회된 데이터가 없습니다.'; + }, + formatRefresh: function () { + return '새로 고침'; + }, + formatToggle: function () { + return '전환'; + }, + formatColumns: function () { + return '컬럼 필터링'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ko-KR']); + +})(jQuery); +/** + * Bootstrap Table Malay translation + * Author: Azamshul Azizy + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ms-MY'] = { + formatLoadingMessage: function () { + return 'Permintaan sedang dimuatkan. Sila tunggu sebentar...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rekod setiap muka surat'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Sedang memaparkan rekod ' + pageFrom + ' hingga ' + pageTo + ' daripada jumlah ' + totalRows + ' rekod'; + }, + formatSearch: function () { + return 'Cari'; + }, + formatNoMatches: function () { + return 'Tiada rekod yang menyamai permintaan'; + }, + formatPaginationSwitch: function () { + return 'Tunjuk/sembunyi muka surat'; + }, + formatRefresh: function () { + return 'Muatsemula'; + }, + formatToggle: function () { + return 'Tukar'; + }, + formatColumns: function () { + return 'Lajur'; + }, + formatAllRows: function () { + return 'Semua'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ms-MY']); + +})(jQuery); + +/** + * Bootstrap Table norwegian translation + * Author: Jim Nordbø, jim@nordb.no + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['nb-NO'] = { + formatLoadingMessage: function () { + return 'Oppdaterer, vennligst vent...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' poster pr side'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Viser ' + pageFrom + ' til ' + pageTo + ' av ' + totalRows + ' rekker'; + }, + formatSearch: function () { + return 'Søk'; + }, + formatNoMatches: function () { + return 'Ingen poster funnet'; + }, + formatRefresh: function () { + return 'Oppdater'; + }, + formatToggle: function () { + return 'Endre'; + }, + formatColumns: function () { + return 'Kolonner'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['nb-NO']); + +})(jQuery); +/** + * Bootstrap Table Dutch translation + * Author: Your Name + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['nl-NL'] = { + formatLoadingMessage: function () { + return 'Laden, even geduld...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' records per pagina'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Toon ' + pageFrom + ' tot ' + pageTo + ' van ' + totalRows + ' record' + ((totalRows > 1) ? 's' : ''); + }, + formatDetailPagination: function (totalRows) { + return 'Toon ' + totalRows + ' record' + ((totalRows > 1) ? 's' : ''); + }, + formatSearch: function () { + return 'Zoeken'; + }, + formatNoMatches: function () { + return 'Geen resultaten gevonden'; + }, + formatRefresh: function () { + return 'Vernieuwen'; + }, + formatToggle: function () { + return 'Omschakelen'; + }, + formatColumns: function () { + return 'Kolommen'; + }, + formatAllRows: function () { + return 'Alle'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['nl-NL']); + +})(jQuery); + +/** + * Bootstrap Table Polish translation + * Author: zergu + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['pl-PL'] = { + formatLoadingMessage: function () { + return 'Ładowanie, proszę czekać...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rekordów na stronę'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Wyświetlanie rekordów od ' + pageFrom + ' do ' + pageTo + ' z ' + totalRows; + }, + formatSearch: function () { + return 'Szukaj'; + }, + formatNoMatches: function () { + return 'Niestety, nic nie znaleziono'; + }, + formatRefresh: function () { + return 'Odśwież'; + }, + formatToggle: function () { + return 'Przełącz'; + }, + formatColumns: function () { + return 'Kolumny'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['pl-PL']); + +})(jQuery); + +/** + * Bootstrap Table Brazilian Portuguese Translation + * Author: Eduardo Cerqueira + * Update: João Mello + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['pt-BR'] = { + formatLoadingMessage: function () { + return 'Carregando, aguarde...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registros por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Exibindo ' + pageFrom + ' até ' + pageTo + ' de ' + totalRows + ' linhas'; + }, + formatSearch: function () { + return 'Pesquisar'; + }, + formatRefresh: function () { + return 'Recarregar'; + }, + formatToggle: function () { + return 'Alternar'; + }, + formatColumns: function () { + return 'Colunas'; + }, + formatPaginationSwitch: function () { + return 'Ocultar/Exibir paginação'; + }, + formatNoMatches: function () { + return 'Nenhum registro encontrado'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['pt-BR']); + +})(jQuery); + +/** + * Bootstrap Table Portuguese Portugal Translation + * Author: Burnspirit + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['pt-PT'] = { + formatLoadingMessage: function () { + return 'A carregar, aguarde...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' registos por página'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'A mostrar ' + pageFrom + ' até ' + pageTo + ' de ' + totalRows + ' linhas'; + }, + formatSearch: function () { + return 'Pesquisa'; + }, + formatNoMatches: function () { + return 'Nenhum registo encontrado'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['pt-PT']); + +})(jQuery); + +/** + * Bootstrap Table Romanian translation + * Author: cristake + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ro-RO'] = { + formatLoadingMessage: function () { + return 'Se incarca, va rugam asteptati...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' inregistrari pe pagina'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Arata de la ' + pageFrom + ' pana la ' + pageTo + ' din ' + totalRows + ' randuri'; + }, + formatSearch: function () { + return 'Cauta'; + }, + formatNoMatches: function () { + return 'Nu au fost gasite inregistrari'; + }, + formatPaginationSwitch: function () { + return 'Ascunde/Arata paginatia'; + }, + formatRefresh: function () { + return 'Reincarca'; + }, + formatToggle: function () { + return 'Comuta'; + }, + formatColumns: function () { + return 'Coloane'; + }, + formatAllRows: function () { + return 'Toate'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ro-RO']); + +})(jQuery); +/** + * Bootstrap Table Russian translation + * Author: Dunaevsky Maxim + */ +(function ($) { + 'use strict'; + $.fn.bootstrapTable.locales['ru-RU'] = { + formatLoadingMessage: function () { + return 'Пожалуйста, подождите, идёт загрузка...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' записей на страницу'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Записи с ' + pageFrom + ' по ' + pageTo + ' из ' + totalRows; + }, + formatSearch: function () { + return 'Поиск'; + }, + formatNoMatches: function () { + return 'Ничего не найдено'; + }, + formatRefresh: function () { + return 'Обновить'; + }, + formatToggle: function () { + return 'Переключить'; + }, + formatColumns: function () { + return 'Колонки'; + }, + formatClearFilters: function () { + return 'Очистить фильтры'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ru-RU']); + +})(jQuery); + +/** + * Bootstrap Table Slovak translation + * Author: Jozef Dúc + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['sk-SK'] = { + formatLoadingMessage: function () { + return 'Prosím čakajte ...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' záznamov na stranu'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Zobrazená ' + pageFrom + '. - ' + pageTo + '. položka z celkových ' + totalRows; + }, + formatSearch: function () { + return 'Vyhľadávanie'; + }, + formatNoMatches: function () { + return 'Nenájdená žiadna vyhovujúca položka'; + }, + formatRefresh: function () { + return 'Obnoviť'; + }, + formatToggle: function () { + return 'Prepni'; + }, + formatColumns: function () { + return 'Stĺpce'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['sk-SK']); + +})(jQuery); + +/** + * Bootstrap Table Swedish translation + * Author: C Bratt + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['sv-SE'] = { + formatLoadingMessage: function () { + return 'Laddar, vänligen vänta...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' rader per sida'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Visa ' + pageFrom + ' till ' + pageTo + ' av ' + totalRows + ' rader'; + }, + formatSearch: function () { + return 'Sök'; + }, + formatNoMatches: function () { + return 'Inga matchande resultat funna.'; + }, + formatRefresh: function () { + return 'Uppdatera'; + }, + formatToggle: function () { + return 'Skifta'; + }, + formatColumns: function () { + return 'kolumn'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['sv-SE']); + +})(jQuery); + +/** + * Bootstrap Table Thai translation + * Author: Monchai S. + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['th-TH'] = { + formatLoadingMessage: function () { + return 'กำลังโหลดข้อมูล, กรุณารอสักครู่...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' รายการต่อหน้า'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'รายการที่ ' + pageFrom + ' ถึง ' + pageTo + ' จากทั้งหมด ' + totalRows + ' รายการ'; + }, + formatSearch: function () { + return 'ค้นหา'; + }, + formatNoMatches: function () { + return 'ไม่พบรายการที่ค้นหา !'; + }, + formatRefresh: function () { + return 'รีเฟรส'; + }, + formatToggle: function () { + return 'สลับมุมมอง'; + }, + formatColumns: function () { + return 'คอลัมน์'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['th-TH']); + +})(jQuery); + +/** + * Bootstrap Table Turkish translation + * Author: Emin Şen + * Author: Sercan Cakir + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['tr-TR'] = { + formatLoadingMessage: function () { + return 'Yükleniyor, lütfen bekleyin...'; + }, + formatRecordsPerPage: function (pageNumber) { + return 'Sayfa başına ' + pageNumber + ' kayıt.'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return totalRows + ' kayıttan ' + pageFrom + '-' + pageTo + ' arası gösteriliyor.'; + }, + formatSearch: function () { + return 'Ara'; + }, + formatNoMatches: function () { + return 'Eşleşen kayıt bulunamadı.'; + }, + formatRefresh: function () { + return 'Yenile'; + }, + formatToggle: function () { + return 'Değiştir'; + }, + formatColumns: function () { + return 'Sütunlar'; + }, + formatAllRows: function () { + return 'Tüm Satırlar'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['tr-TR']); + +})(jQuery); + +/** + * Bootstrap Table Ukrainian translation + * Author: Vitaliy Timchenko + */ + (function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['uk-UA'] = { + formatLoadingMessage: function () { + return 'Завантаження, будь ласка, зачекайте...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' записів на сторінку'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Показано з ' + pageFrom + ' по ' + pageTo + '. Всього: ' + totalRows; + }, + formatSearch: function () { + return 'Пошук'; + }, + formatNoMatches: function () { + return 'Не знайдено жодного запису'; + }, + formatRefresh: function () { + return 'Оновити'; + }, + formatToggle: function () { + return 'Змінити'; + }, + formatColumns: function () { + return 'Стовпці'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['uk-UA']); + +})(jQuery); + +/** + * Bootstrap Table Urdu translation + * Author: Malik + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['ur-PK'] = { + formatLoadingMessage: function () { + return 'براۓ مہربانی انتظار کیجئے'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' ریکارڈز فی صفہ '; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'دیکھیں ' + pageFrom + ' سے ' + pageTo + ' کے ' + totalRows + 'ریکارڈز'; + }, + formatSearch: function () { + return 'تلاش'; + }, + formatNoMatches: function () { + return 'کوئی ریکارڈ نہیں ملا'; + }, + formatRefresh: function () { + return 'تازہ کریں'; + }, + formatToggle: function () { + return 'تبدیل کریں'; + }, + formatColumns: function () { + return 'کالم'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['ur-PK']); + +})(jQuery); + +/** + * Bootstrap Table Vietnamese translation + * Author: Duc N. PHAM + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['vi-VN'] = { + formatLoadingMessage: function () { + return 'Đang tải...'; + }, + formatRecordsPerPage: function (pageNumber) { + return pageNumber + ' bản ghi mỗi trang'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return 'Hiển thị từ trang ' + pageFrom + ' đến ' + pageTo + ' của ' + totalRows + ' bảng ghi'; + }, + formatSearch: function () { + return 'Tìm kiếm'; + }, + formatNoMatches: function () { + return 'Không có dữ liệu'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['vi-VN']); + +})(jQuery); +/** + * Bootstrap Table Chinese translation + * Author: Zhixin Wen + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['zh-CN'] = { + formatLoadingMessage: function () { + return '正在努力地加载数据中,请稍候……'; + }, + formatRecordsPerPage: function (pageNumber) { + return '每页显示 ' + pageNumber + ' 条记录'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return '显示第 ' + pageFrom + ' 到第 ' + pageTo + ' 条记录,总共 ' + totalRows + ' 条记录'; + }, + formatSearch: function () { + return '搜索'; + }, + formatNoMatches: function () { + return '没有找到匹配的记录'; + }, + formatPaginationSwitch: function () { + return '隐藏/显示分页'; + }, + formatRefresh: function () { + return '刷新'; + }, + formatToggle: function () { + return '切换'; + }, + formatColumns: function () { + return '列'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-CN']); + +})(jQuery); +/** + * Bootstrap Table Chinese translation + * Author: Zhixin Wen + */ +(function ($) { + 'use strict'; + + $.fn.bootstrapTable.locales['zh-TW'] = { + formatLoadingMessage: function () { + return '正在努力地載入資料,請稍候……'; + }, + formatRecordsPerPage: function (pageNumber) { + return '每頁顯示 ' + pageNumber + ' 項記錄'; + }, + formatShowingRows: function (pageFrom, pageTo, totalRows) { + return '顯示第 ' + pageFrom + ' 到第 ' + pageTo + ' 項記錄,總共 ' + totalRows + ' 項記錄'; + }, + formatSearch: function () { + return '搜尋'; + }, + formatNoMatches: function () { + return '沒有找到符合的結果'; + }, + formatPaginationSwitch: function () { + return '隱藏/顯示分頁'; + }, + formatRefresh: function () { + return '重新整理'; + }, + formatToggle: function () { + return '切換'; + }, + formatColumns: function () { + return '列'; + } + }; + + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-TW']); + +})(jQuery); diff --git a/resources/assets/js/bootstrap-table-locale-all.min.js b/resources/assets/js/bootstrap-table-locale-all.min.js new file mode 100755 index 0000000000..38d47669de --- /dev/null +++ b/resources/assets/js/bootstrap-table-locale-all.min.js @@ -0,0 +1,7 @@ +/* +* bootstrap-table - v1.10.1 - 2016-02-17 +* https://github.com/wenzhixin/bootstrap-table +* Copyright (c) 2016 zhixin wen +* Licensed MIT License +*/ +!function(a){"use strict";a.fn.bootstrapTable.locales["af-ZA"]={formatLoadingMessage:function(){return"Besig om te laai, wag asseblief ..."},formatRecordsPerPage:function(a){return a+" rekords per bladsy"},formatShowingRows:function(a,b,c){return"Resultate "+a+" tot "+b+" van "+c+" rye"},formatSearch:function(){return"Soek"},formatNoMatches:function(){return"Geen rekords gevind nie"},formatPaginationSwitch:function(){return"Wys/verberg bladsy nummering"},formatRefresh:function(){return"Herlaai"},formatToggle:function(){return"Wissel"},formatColumns:function(){return"Kolomme"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["af-ZA"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ar-SA"]={formatLoadingMessage:function(){return"جاري التحميل, يرجى الإنتظار..."},formatRecordsPerPage:function(a){return a+" سجل لكل صفحة"},formatShowingRows:function(a,b,c){return"الظاهر "+a+" إلى "+b+" من "+c+" سجل"},formatSearch:function(){return"بحث"},formatNoMatches:function(){return"لا توجد نتائج مطابقة للبحث"},formatPaginationSwitch:function(){return"إخفاءإظهار ترقيم الصفحات"},formatRefresh:function(){return"تحديث"},formatToggle:function(){return"تغيير"},formatColumns:function(){return"أعمدة"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ar-SA"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ca-ES"]={formatLoadingMessage:function(){return"Espereu, si us plau..."},formatRecordsPerPage:function(a){return a+" resultats per pàgina"},formatShowingRows:function(a,b,c){return"Mostrant de "+a+" fins "+b+" - total "+c+" resultats"},formatSearch:function(){return"Cerca"},formatNoMatches:function(){return"No s'han trobat resultats"},formatPaginationSwitch:function(){return"Amaga/Mostra paginació"},formatRefresh:function(){return"Refresca"},formatToggle:function(){return"Alterna formatació"},formatColumns:function(){return"Columnes"},formatAllRows:function(){return"Tots"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ca-ES"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["cs-CZ"]={formatLoadingMessage:function(){return"Čekejte, prosím..."},formatRecordsPerPage:function(a){return a+" položek na stránku"},formatShowingRows:function(a,b,c){return"Zobrazena "+a+". - "+b+". položka z celkových "+c},formatSearch:function(){return"Vyhledávání"},formatNoMatches:function(){return"Nenalezena žádná vyhovující položka"},formatPaginationSwitch:function(){return"Skrýt/Zobrazit stránkování"},formatRefresh:function(){return"Aktualizovat"},formatToggle:function(){return"Přepni"},formatColumns:function(){return"Sloupce"},formatAllRows:function(){return"Vše"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["cs-CZ"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["da-DK"]={formatLoadingMessage:function(){return"Indlæser, vent venligst..."},formatRecordsPerPage:function(a){return a+" poster pr side"},formatShowingRows:function(a,b,c){return"Viser "+a+" til "+b+" af "+c+" rækker"},formatSearch:function(){return"Søg"},formatNoMatches:function(){return"Ingen poster fundet"},formatRefresh:function(){return"Opdater"},formatToggle:function(){return"Skift"},formatColumns:function(){return"Kolonner"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["da-DK"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["de-DE"]={formatLoadingMessage:function(){return"Lade, bitte warten..."},formatRecordsPerPage:function(a){return a+" Einträge pro Seite"},formatShowingRows:function(a,b,c){return"Zeige "+a+" bis "+b+" von "+c+" Zeile"+(c>1?"n":"")},formatSearch:function(){return"Suchen"},formatNoMatches:function(){return"Keine passenden Ergebnisse gefunden"},formatRefresh:function(){return"Neu laden"},formatToggle:function(){return"Umschalten"},formatColumns:function(){return"Spalten"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["de-DE"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["el-GR"]={formatLoadingMessage:function(){return"Φορτώνει, παρακαλώ περιμένετε..."},formatRecordsPerPage:function(a){return a+" αποτελέσματα ανά σελίδα"},formatShowingRows:function(a,b,c){return"Εμφανίζονται από την "+a+" ως την "+b+" από σύνολο "+c+" σειρών"},formatSearch:function(){return"Αναζητήστε"},formatNoMatches:function(){return"Δεν βρέθηκαν αποτελέσματα"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["el-GR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["en-US"]={formatLoadingMessage:function(){return"Loading, please wait..."},formatRecordsPerPage:function(a){return a+" rows per page"},formatShowingRows:function(a,b,c){return"Showing "+a+" to "+b+" of "+c+" rows"},formatSearch:function(){return"Search"},formatNoMatches:function(){return"No matching records found"},formatPaginationSwitch:function(){return"Hide/Show pagination"},formatRefresh:function(){return"Refresh"},formatToggle:function(){return"Toggle"},formatColumns:function(){return"Columns"},formatAllRows:function(){return"All"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["en-US"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-AR"]={formatLoadingMessage:function(){return"Cargando, espere por favor..."},formatRecordsPerPage:function(a){return a+" registros por página"},formatShowingRows:function(a,b,c){return"Mostrando "+a+" a "+b+" de "+c+" filas"},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se encontraron registros"},formatAllRows:function(){return"Todo"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-AR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-CR"]={formatLoadingMessage:function(){return"Cargando, por favor espere..."},formatRecordsPerPage:function(a){return a+" registros por página"},formatShowingRows:function(a,b,c){return"Mostrando de "+a+" a "+b+" registros de "+c+" registros en total"},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se encontraron registros"},formatRefresh:function(){return"Refrescar"},formatToggle:function(){return"Alternar"},formatColumns:function(){return"Columnas"},formatAllRows:function(){return"Todo"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-CR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-ES"]={formatLoadingMessage:function(){return"Por favor espere..."},formatRecordsPerPage:function(a){return a+" resultados por página"},formatShowingRows:function(a,b,c){return"Mostrando desde "+a+" hasta "+b+" - En total "+c+" resultados"},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se encontraron resultados"},formatPaginationSwitch:function(){return"Ocultar/Mostrar paginación"},formatRefresh:function(){return"Refrescar"},formatToggle:function(){return"Ocultar/Mostrar"},formatColumns:function(){return"Columnas"},formatAllRows:function(){return"Todos"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-ES"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-MX"]={formatLoadingMessage:function(){return"Cargando, espere por favor..."},formatRecordsPerPage:function(a){return a+" registros por página"},formatShowingRows:function(a,b,c){return"Mostrando "+a+" a "+b+" de "+c+" filas"},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se encontraron registros"},formatAllRows:function(){return"Todo"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-MX"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-NI"]={formatLoadingMessage:function(){return"Cargando, por favor espere..."},formatRecordsPerPage:function(a){return a+" registros por página"},formatShowingRows:function(a,b,c){return"Mostrando de "+a+" a "+b+" registros de "+c+" registros en total"},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se encontraron registros"},formatRefresh:function(){return"Refrescar"},formatToggle:function(){return"Alternar"},formatColumns:function(){return"Columnas"},formatAllRows:function(){return"Todo"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-NI"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["es-SP"]={formatLoadingMessage:function(){return"Cargando, por favor espera..."},formatRecordsPerPage:function(a){return a+" registros por página."},formatShowingRows:function(a,b,c){return a+" - "+b+" de "+c+" registros."},formatSearch:function(){return"Buscar"},formatNoMatches:function(){return"No se han encontrado registros."},formatRefresh:function(){return"Actualizar"},formatToggle:function(){return"Alternar"},formatColumns:function(){return"Columnas"},formatAllRows:function(){return"Todo"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["es-SP"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["et-EE"]={formatLoadingMessage:function(){return"Päring käib, palun oota..."},formatRecordsPerPage:function(a){return a+" rida lehe kohta"},formatShowingRows:function(a,b,c){return"Näitan tulemusi "+a+" kuni "+b+" - kokku "+c+" tulemust"},formatSearch:function(){return"Otsi"},formatNoMatches:function(){return"Päringu tingimustele ei vastanud ühtegi tulemust"},formatPaginationSwitch:function(){return"Näita/Peida lehtedeks jagamine"},formatRefresh:function(){return"Värskenda"},formatToggle:function(){return"Lülita"},formatColumns:function(){return"Veerud"},formatAllRows:function(){return"Kõik"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["et-EE"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["fa-IR"]={formatLoadingMessage:function(){return"در حال بارگذاری, لطفا صبر کنید..."},formatRecordsPerPage:function(a){return a+" رکورد در صفحه"},formatShowingRows:function(a,b,c){return"نمایش "+a+" تا "+b+" از "+c+" ردیف"},formatSearch:function(){return"جستجو"},formatNoMatches:function(){return"رکوردی یافت نشد."},formatPaginationSwitch:function(){return"نمایش/مخفی صفحه بندی"},formatRefresh:function(){return"به روز رسانی"},formatToggle:function(){return"تغییر نمایش"},formatColumns:function(){return"سطر ها"},formatAllRows:function(){return"همه"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["fa-IR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["fr-BE"]={formatLoadingMessage:function(){return"Chargement en cours..."},formatRecordsPerPage:function(a){return a+" entrées par page"},formatShowingRows:function(a,b,c){return"Affiche de"+a+" à "+b+" sur "+c+" lignes"},formatSearch:function(){return"Recherche"},formatNoMatches:function(){return"Pas de fichiers trouvés"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["fr-BE"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["fr-FR"]={formatLoadingMessage:function(){return"Chargement en cours, patientez, s´il vous plaît ..."},formatRecordsPerPage:function(a){return a+" lignes par page"},formatShowingRows:function(a,b,c){return"Affichage des lignes "+a+" à "+b+" sur "+c+" lignes au total"},formatSearch:function(){return"Rechercher"},formatNoMatches:function(){return"Aucun résultat trouvé"},formatRefresh:function(){return"Rafraîchir"},formatToggle:function(){return"Alterner"},formatColumns:function(){return"Colonnes"},formatAllRows:function(){return"Tous"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["fr-FR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["he-IL"]={formatLoadingMessage:function(){return"טוען, נא להמתין..."},formatRecordsPerPage:function(a){return a+" שורות בעמוד"},formatShowingRows:function(a,b,c){return"מציג "+a+" עד "+b+" מ-"+c+" שורות"},formatSearch:function(){return"חיפוש"},formatNoMatches:function(){return"לא נמצאו רשומות תואמות"},formatPaginationSwitch:function(){return"הסתר/הצג מספור דפים"},formatRefresh:function(){return"רענן"},formatToggle:function(){return"החלף תצוגה"},formatColumns:function(){return"עמודות"},formatAllRows:function(){return"הכל"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["he-IL"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["hr-HR"]={formatLoadingMessage:function(){return"Molimo pričekajte ..."},formatRecordsPerPage:function(a){return a+" broj zapisa po stranici"},formatShowingRows:function(a,b,c){return"Prikazujem "+a+". - "+b+". od ukupnog broja zapisa "+c},formatSearch:function(){return"Pretraži"},formatNoMatches:function(){return"Nije pronađen niti jedan zapis"},formatPaginationSwitch:function(){return"Prikaži/sakrij stranice"},formatRefresh:function(){return"Osvježi"},formatToggle:function(){return"Promijeni prikaz"},formatColumns:function(){return"Kolone"},formatAllRows:function(){return"Sve"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["hr-HR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["hu-HU"]={formatLoadingMessage:function(){return"Betöltés, kérem várjon..."},formatRecordsPerPage:function(a){return a+" rekord per oldal"},formatShowingRows:function(a,b,c){return"Megjelenítve "+a+" - "+b+" / "+c+" összesen"},formatSearch:function(){return"Keresés"},formatNoMatches:function(){return"Nincs találat"},formatPaginationSwitch:function(){return"Lapozó elrejtése/megjelenítése"},formatRefresh:function(){return"Frissítés"},formatToggle:function(){return"Összecsuk/Kinyit"},formatColumns:function(){return"Oszlopok"},formatAllRows:function(){return"Összes"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["hu-HU"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["it-IT"]={formatLoadingMessage:function(){return"Caricamento in corso..."},formatRecordsPerPage:function(a){return a+" elementi per pagina"},formatShowingRows:function(a,b,c){return"Pagina "+a+" di "+b+" ("+c+" records)"},formatSearch:function(){return"Cerca"},formatNoMatches:function(){return"Nessun elemento trovato"},formatRefresh:function(){return"Aggiorna"},formatToggle:function(){return"Alterna"},formatColumns:function(){return"Colonne"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["it-IT"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ja-JP"]={formatLoadingMessage:function(){return"読み込み中です。少々お待ちください。"},formatRecordsPerPage:function(a){return"ページ当たり最大"+a+"件"},formatShowingRows:function(a,b,c){return"全"+c+"件から、"+a+"から"+b+"件目まで表示しています"},formatSearch:function(){return"検索"},formatNoMatches:function(){return"該当するレコードが見つかりません"},formatPaginationSwitch:function(){return"ページ数を表示・非表示"},formatRefresh:function(){return"更新"},formatToggle:function(){return"トグル"},formatColumns:function(){return"列"},formatAllRows:function(){return"すべて"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ja-JP"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ka-GE"]={formatLoadingMessage:function(){return"იტვირთება, გთხოვთ მოიცადოთ..."},formatRecordsPerPage:function(a){return a+" ჩანაწერი თითო გვერდზე"},formatShowingRows:function(a,b,c){return"ნაჩვენებია "+a+"-დან "+b+"-მდე ჩანაწერი ჯამური "+c+"-დან"},formatSearch:function(){return"ძებნა"},formatNoMatches:function(){return"მონაცემები არ არის"},formatPaginationSwitch:function(){return"გვერდების გადამრთველის დამალვა/გამოჩენა"},formatRefresh:function(){return"განახლება"},formatToggle:function(){return"ჩართვა/გამორთვა"},formatColumns:function(){return"სვეტები"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ka-GE"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ko-KR"]={formatLoadingMessage:function(){return"데이터를 불러오는 중입니다..."},formatRecordsPerPage:function(a){return"페이지 당 "+a+"개 데이터 출력"},formatShowingRows:function(a,b,c){return"전체 "+c+"개 중 "+a+"~"+b+"번째 데이터 출력,"},formatSearch:function(){return"검색"},formatNoMatches:function(){return"조회된 데이터가 없습니다."},formatRefresh:function(){return"새로 고침"},formatToggle:function(){return"전환"},formatColumns:function(){return"컬럼 필터링"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ko-KR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ms-MY"]={formatLoadingMessage:function(){return"Permintaan sedang dimuatkan. Sila tunggu sebentar..."},formatRecordsPerPage:function(a){return a+" rekod setiap muka surat"},formatShowingRows:function(a,b,c){return"Sedang memaparkan rekod "+a+" hingga "+b+" daripada jumlah "+c+" rekod"},formatSearch:function(){return"Cari"},formatNoMatches:function(){return"Tiada rekod yang menyamai permintaan"},formatPaginationSwitch:function(){return"Tunjuk/sembunyi muka surat"},formatRefresh:function(){return"Muatsemula"},formatToggle:function(){return"Tukar"},formatColumns:function(){return"Lajur"},formatAllRows:function(){return"Semua"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ms-MY"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["nb-NO"]={formatLoadingMessage:function(){return"Oppdaterer, vennligst vent..."},formatRecordsPerPage:function(a){return a+" poster pr side"},formatShowingRows:function(a,b,c){return"Viser "+a+" til "+b+" av "+c+" rekker"},formatSearch:function(){return"Søk"},formatNoMatches:function(){return"Ingen poster funnet"},formatRefresh:function(){return"Oppdater"},formatToggle:function(){return"Endre"},formatColumns:function(){return"Kolonner"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["nb-NO"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["nl-NL"]={formatLoadingMessage:function(){return"Laden, even geduld..."},formatRecordsPerPage:function(a){return a+" records per pagina"},formatShowingRows:function(a,b,c){return"Toon "+a+" tot "+b+" van "+c+" record"+(c>1?"s":"")},formatDetailPagination:function(a){return"Toon "+a+" record"+(a>1?"s":"")},formatSearch:function(){return"Zoeken"},formatNoMatches:function(){return"Geen resultaten gevonden"},formatRefresh:function(){return"Vernieuwen"},formatToggle:function(){return"Omschakelen"},formatColumns:function(){return"Kolommen"},formatAllRows:function(){return"Alle"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["nl-NL"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["pl-PL"]={formatLoadingMessage:function(){return"Ładowanie, proszę czekać..."},formatRecordsPerPage:function(a){return a+" rekordów na stronę"},formatShowingRows:function(a,b,c){return"Wyświetlanie rekordów od "+a+" do "+b+" z "+c},formatSearch:function(){return"Szukaj"},formatNoMatches:function(){return"Niestety, nic nie znaleziono"},formatRefresh:function(){return"Odśwież"},formatToggle:function(){return"Przełącz"},formatColumns:function(){return"Kolumny"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["pl-PL"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["pt-BR"]={formatLoadingMessage:function(){return"Carregando, aguarde..."},formatRecordsPerPage:function(a){return a+" registros por página"},formatShowingRows:function(a,b,c){return"Exibindo "+a+" até "+b+" de "+c+" linhas"},formatSearch:function(){return"Pesquisar"},formatRefresh:function(){return"Recarregar"},formatToggle:function(){return"Alternar"},formatColumns:function(){return"Colunas"},formatPaginationSwitch:function(){return"Ocultar/Exibir paginação"},formatNoMatches:function(){return"Nenhum registro encontrado"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["pt-BR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["pt-PT"]={formatLoadingMessage:function(){return"A carregar, aguarde..."},formatRecordsPerPage:function(a){return a+" registos por página"},formatShowingRows:function(a,b,c){return"A mostrar "+a+" até "+b+" de "+c+" linhas"},formatSearch:function(){return"Pesquisa"},formatNoMatches:function(){return"Nenhum registo encontrado"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["pt-PT"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ro-RO"]={formatLoadingMessage:function(){return"Se incarca, va rugam asteptati..."},formatRecordsPerPage:function(a){return a+" inregistrari pe pagina"},formatShowingRows:function(a,b,c){return"Arata de la "+a+" pana la "+b+" din "+c+" randuri"},formatSearch:function(){return"Cauta"},formatNoMatches:function(){return"Nu au fost gasite inregistrari"},formatPaginationSwitch:function(){return"Ascunde/Arata paginatia"},formatRefresh:function(){return"Reincarca"},formatToggle:function(){return"Comuta"},formatColumns:function(){return"Coloane"},formatAllRows:function(){return"Toate"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ro-RO"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ru-RU"]={formatLoadingMessage:function(){return"Пожалуйста, подождите, идёт загрузка..."},formatRecordsPerPage:function(a){return a+" записей на страницу"},formatShowingRows:function(a,b,c){return"Записи с "+a+" по "+b+" из "+c},formatSearch:function(){return"Поиск"},formatNoMatches:function(){return"Ничего не найдено"},formatRefresh:function(){return"Обновить"},formatToggle:function(){return"Переключить"},formatColumns:function(){return"Колонки"},formatClearFilters:function(){return"Очистить фильтры"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ru-RU"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["sk-SK"]={formatLoadingMessage:function(){return"Prosím čakajte ..."},formatRecordsPerPage:function(a){return a+" záznamov na stranu"},formatShowingRows:function(a,b,c){return"Zobrazená "+a+". - "+b+". položka z celkových "+c},formatSearch:function(){return"Vyhľadávanie"},formatNoMatches:function(){return"Nenájdená žiadna vyhovujúca položka"},formatRefresh:function(){return"Obnoviť"},formatToggle:function(){return"Prepni"},formatColumns:function(){return"Stĺpce"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["sk-SK"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["sv-SE"]={formatLoadingMessage:function(){return"Laddar, vänligen vänta..."},formatRecordsPerPage:function(a){return a+" rader per sida"},formatShowingRows:function(a,b,c){return"Visa "+a+" till "+b+" av "+c+" rader"},formatSearch:function(){return"Sök"},formatNoMatches:function(){return"Inga matchande resultat funna."},formatRefresh:function(){return"Uppdatera"},formatToggle:function(){return"Skifta"},formatColumns:function(){return"kolumn"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["sv-SE"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["th-TH"]={formatLoadingMessage:function(){return"กำลังโหลดข้อมูล, กรุณารอสักครู่..."},formatRecordsPerPage:function(a){return a+" รายการต่อหน้า"},formatShowingRows:function(a,b,c){return"รายการที่ "+a+" ถึง "+b+" จากทั้งหมด "+c+" รายการ"},formatSearch:function(){return"ค้นหา"},formatNoMatches:function(){return"ไม่พบรายการที่ค้นหา !"},formatRefresh:function(){return"รีเฟรส"},formatToggle:function(){return"สลับมุมมอง"},formatColumns:function(){return"คอลัมน์"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["th-TH"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["tr-TR"]={formatLoadingMessage:function(){return"Yükleniyor, lütfen bekleyin..."},formatRecordsPerPage:function(a){return"Sayfa başına "+a+" kayıt."},formatShowingRows:function(a,b,c){return c+" kayıttan "+a+"-"+b+" arası gösteriliyor."},formatSearch:function(){return"Ara"},formatNoMatches:function(){return"Eşleşen kayıt bulunamadı."},formatRefresh:function(){return"Yenile"},formatToggle:function(){return"Değiştir"},formatColumns:function(){return"Sütunlar"},formatAllRows:function(){return"Tüm Satırlar"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["tr-TR"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["uk-UA"]={formatLoadingMessage:function(){return"Завантаження, будь ласка, зачекайте..."},formatRecordsPerPage:function(a){return a+" записів на сторінку"},formatShowingRows:function(a,b,c){return"Показано з "+a+" по "+b+". Всього: "+c},formatSearch:function(){return"Пошук"},formatNoMatches:function(){return"Не знайдено жодного запису"},formatRefresh:function(){return"Оновити"},formatToggle:function(){return"Змінити"},formatColumns:function(){return"Стовпці"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["uk-UA"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["ur-PK"]={formatLoadingMessage:function(){return"براۓ مہربانی انتظار کیجئے"},formatRecordsPerPage:function(a){return a+" ریکارڈز فی صفہ "},formatShowingRows:function(a,b,c){return"دیکھیں "+a+" سے "+b+" کے "+c+"ریکارڈز"},formatSearch:function(){return"تلاش"},formatNoMatches:function(){return"کوئی ریکارڈ نہیں ملا"},formatRefresh:function(){return"تازہ کریں"},formatToggle:function(){return"تبدیل کریں"},formatColumns:function(){return"کالم"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["ur-PK"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["vi-VN"]={formatLoadingMessage:function(){return"Đang tải..."},formatRecordsPerPage:function(a){return a+" bản ghi mỗi trang"},formatShowingRows:function(a,b,c){return"Hiển thị từ trang "+a+" đến "+b+" của "+c+" bảng ghi"},formatSearch:function(){return"Tìm kiếm"},formatNoMatches:function(){return"Không có dữ liệu"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["vi-VN"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["zh-CN"]={formatLoadingMessage:function(){return"正在努力地加载数据中,请稍候……"},formatRecordsPerPage:function(a){return"每页显示 "+a+" 条记录"},formatShowingRows:function(a,b,c){return"显示第 "+a+" 到第 "+b+" 条记录,总共 "+c+" 条记录"},formatSearch:function(){return"搜索"},formatNoMatches:function(){return"没有找到匹配的记录"},formatPaginationSwitch:function(){return"隐藏/显示分页"},formatRefresh:function(){return"刷新"},formatToggle:function(){return"切换"},formatColumns:function(){return"列"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["zh-CN"])}(jQuery),function(a){"use strict";a.fn.bootstrapTable.locales["zh-TW"]={formatLoadingMessage:function(){return"正在努力地載入資料,請稍候……"},formatRecordsPerPage:function(a){return"每頁顯示 "+a+" 項記錄"},formatShowingRows:function(a,b,c){return"顯示第 "+a+" 到第 "+b+" 項記錄,總共 "+c+" 項記錄"},formatSearch:function(){return"搜尋"},formatNoMatches:function(){return"沒有找到符合的結果"},formatPaginationSwitch:function(){return"隱藏/顯示分頁"},formatRefresh:function(){return"重新整理"},formatToggle:function(){return"切換"},formatColumns:function(){return"列"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["zh-TW"])}(jQuery); \ No newline at end of file diff --git a/resources/assets/js/bootstrap-table.css b/resources/assets/js/bootstrap-table.css new file mode 100755 index 0000000000..b557667625 --- /dev/null +++ b/resources/assets/js/bootstrap-table.css @@ -0,0 +1,302 @@ +/** + * @author zhixin wen + * version: 1.10.1 + * https://github.com/wenzhixin/bootstrap-table/ + */ + +.bootstrap-table .table { + margin-bottom: 0 !important; + border-bottom: 1px solid #dddddd; + border-collapse: collapse !important; + border-radius: 1px; +} + +.bootstrap-table .table:not(.table-condensed), +.bootstrap-table .table:not(.table-condensed) > tbody > tr > th, +.bootstrap-table .table:not(.table-condensed) > tfoot > tr > th, +.bootstrap-table .table:not(.table-condensed) > thead > tr > td, +.bootstrap-table .table:not(.table-condensed) > tbody > tr > td, +.bootstrap-table .table:not(.table-condensed) > tfoot > tr > td { + padding: 8px; +} + +.bootstrap-table .table.table-no-bordered > thead > tr > th, +.bootstrap-table .table.table-no-bordered > tbody > tr > td { + border-right: 2px solid transparent; +} + +.fixed-table-container { + position: relative; + clear: both; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; +} + +.fixed-table-container.table-no-bordered { + border: 1px solid transparent; +} + +.fixed-table-footer, +.fixed-table-header { + overflow: hidden; +} + +.fixed-table-footer { + border-top: 1px solid #dddddd; +} + +.fixed-table-body { + overflow-x: auto; + overflow-y: auto; + height: 100%; +} + +.fixed-table-container table { + width: 100%; +} + +.fixed-table-container thead th { + height: 0; + padding: 0; + margin: 0; + border-left: 1px solid #dddddd; +} + +.fixed-table-container thead th:focus { + outline: 0 solid transparent; +} + +.fixed-table-container thead th:first-child { + border-left: none; + border-top-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.fixed-table-container thead th .th-inner, +.fixed-table-container tbody td .th-inner { + padding: 8px; + line-height: 24px; + vertical-align: top; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.fixed-table-container thead th .sortable { + cursor: pointer; + background-position: right; + background-repeat: no-repeat; + padding-right: 30px; +} + +.fixed-table-container thead th .both { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC'); +} + +.fixed-table-container thead th .asc { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg=='); +} + +.fixed-table-container thead th .desc { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= '); +} + +.fixed-table-container th.detail { + width: 30px; +} + +.fixed-table-container tbody td { + border-left: 1px solid #dddddd; +} + +.fixed-table-container tbody tr:first-child td { + border-top: none; +} + +.fixed-table-container tbody td:first-child { + border-left: none; +} + +/* the same color with .active */ +.fixed-table-container tbody .selected td { + background-color: #f5f5f5; +} + +.fixed-table-container .bs-checkbox { + text-align: center; +} + +.fixed-table-container .bs-checkbox .th-inner { + padding: 8px 0; +} + +.fixed-table-container input[type="radio"], +.fixed-table-container input[type="checkbox"] { + margin: 0 auto !important; +} + +.fixed-table-container .no-records-found { + text-align: center; +} + +.fixed-table-pagination div.pagination, +.fixed-table-pagination .pagination-detail { + margin-top: 10px; + margin-bottom: 10px; +} + +.fixed-table-pagination div.pagination .pagination { + margin: 0; +} + +.fixed-table-pagination .pagination a { + padding: 6px 12px; + line-height: 1.428571429; +} + +.fixed-table-pagination .pagination-info { + line-height: 34px; + margin-right: 5px; +} + +.fixed-table-pagination .btn-group { + position: relative; + display: inline-block; + vertical-align: middle; +} + +.fixed-table-pagination .dropup .dropdown-menu { + margin-bottom: 0; +} + +.fixed-table-pagination .page-list { + display: inline-block; +} + +.fixed-table-toolbar .columns-left { + margin-right: 5px; +} + +.fixed-table-toolbar .columns-right { + margin-left: 5px; +} + +.fixed-table-toolbar .columns label { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; +} + +.fixed-table-toolbar .bars, +.fixed-table-toolbar .search, +.fixed-table-toolbar .columns { + position: relative; + margin-top: 10px; + margin-bottom: 10px; + line-height: 34px; +} + +.fixed-table-pagination li.disabled a { + pointer-events: none; + cursor: default; +} + +.fixed-table-loading { + display: none; + position: absolute; + top: 42px; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + background-color: #fff; + text-align: center; +} + +.fixed-table-body .card-view .title { + font-weight: bold; + display: inline-block; + min-width: 30%; + text-align: left !important; +} + +/* support bootstrap 2 */ +.fixed-table-body thead th .th-inner { + box-sizing: border-box; +} + +.table th, .table td { + vertical-align: middle; + box-sizing: border-box; +} + +.fixed-table-toolbar .dropdown-menu { + text-align: left; + max-height: 300px; + overflow: auto; +} + +.fixed-table-toolbar .btn-group > .btn-group { + display: inline-block; + margin-left: -1px !important; +} + +.fixed-table-toolbar .btn-group > .btn-group > .btn { + border-radius: 0; +} + +.fixed-table-toolbar .btn-group > .btn-group:first-child > .btn { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.fixed-table-toolbar .btn-group > .btn-group:last-child > .btn { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.bootstrap-table .table > thead > tr > th { + vertical-align: bottom; + border-bottom: 1px solid #ddd; +} + +/* support bootstrap 3 */ +.bootstrap-table .table thead > tr > th { + padding: 0; + margin: 0; +} + +.bootstrap-table .fixed-table-footer tbody > tr > td { + padding: 0 !important; +} + +.bootstrap-table .fixed-table-footer .table { + border-bottom: none; + border-radius: 0; + padding: 0 !important; +} + +.pull-right .dropdown-menu { + right: 0; + left: auto; +} + +/* calculate scrollbar width */ +p.fixed-table-scroll-inner { + width: 100%; + height: 200px; +} + +div.fixed-table-scroll-outer { + top: 0; + left: 0; + visibility: hidden; + width: 200px; + height: 150px; + overflow: hidden; +} diff --git a/resources/assets/js/bootstrap-table.js b/resources/assets/js/bootstrap-table.js index f8715e9c4d..17fcd81b9b 100755 --- a/resources/assets/js/bootstrap-table.js +++ b/resources/assets/js/bootstrap-table.js @@ -1,10 +1,10 @@ /** * @author zhixin wen - * version: 1.9.1 + * version: 1.11.1 * https://github.com/wenzhixin/bootstrap-table/ */ -!function ($) { +(function ($) { 'use strict'; // TOOLS DEFINITION @@ -140,7 +140,7 @@ return func; } if (typeof func === 'function') { - return func.apply(self, args); + return func.apply(self, args || []); } if (!func && typeof name === 'string' && sprintf.apply(this, [name].concat(args))) { return sprintf.apply(this, [name].concat(args)); @@ -180,25 +180,16 @@ var escapeHTML = function (text) { if (typeof text === 'string') { return text - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/`/g, '`'); } return text; }; - var getRealHeight = function ($el) { - var height = 0; - $el.children().each(function () { - if (height < $(this).outerHeight(true)) { - height = $(this).outerHeight(true); - } - }); - return height; - }; - var getRealDataAttr = function (dataAttr) { for (var attr in dataAttr) { var auxAttr = attr.split(/(?=[A-Z])/).join('-').toLowerCase(); @@ -211,17 +202,66 @@ return dataAttr; }; - var getItemField = function (item, field) { + var getItemField = function (item, field, escape) { var value = item; if (typeof field !== 'string' || item.hasOwnProperty(field)) { - return item[field]; + return escape ? escapeHTML(item[field]) : item[field]; } var props = field.split('.'); for (var p in props) { - value = value[props[p]]; + if (props.hasOwnProperty(p)) { + value = value && value[props[p]]; + } + } + return escape ? escapeHTML(value) : value; + }; + + var isIEBrowser = function () { + return !!(navigator.userAgent.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)); + }; + + var objectKeys = function () { + // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys + if (!Object.keys) { + Object.keys = (function() { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function(obj) { + if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = [], prop, i; + + for (prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + + if (hasDontEnumBug) { + for (i = 0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + }()); } - return value; }; // BOOTSTRAP TABLE CLASS DEFINITION @@ -239,14 +279,17 @@ BootstrapTable.DEFAULTS = { classes: 'table table-hover', + sortClass: undefined, locale: undefined, height: undefined, undefinedText: '-', sortName: undefined, sortOrder: 'asc', + sortStable: false, striped: false, columns: [[]], data: [], + totalField: 'total', dataField: 'rows', method: 'get', url: undefined, @@ -264,6 +307,7 @@ }, pagination: false, onlyInfoPagination: false, + paginationLoop: true, sidePagination: 'client', // client or server totalRows: 0, // server side need to set pageNumber: 1, @@ -272,11 +316,10 @@ paginationHAlign: 'right', //right, left paginationVAlign: 'bottom', //bottom, top, both paginationDetailHAlign: 'left', //right, left - paginationFirstText: '«', paginationPreText: '‹', paginationNextText: '›', - paginationLastText: '»', search: false, + searchOnEnterKey: false, strictSearch: false, searchAlign: 'right', selectItemName: 'btSelectItem', @@ -288,6 +331,7 @@ showToggle: false, buttonsAlign: 'right', smartDisplay: true, + escape: false, minimumCountColumns: 1, idField: undefined, uniqueId: undefined, @@ -308,6 +352,7 @@ searchTimeOut: 500, searchText: '', iconSize: undefined, + buttonsClass: 'default', iconsPrefix: 'glyphicon', // glyphicon of fa (font awesome) icons: { paginationSwitchDown: 'glyphicon-collapse-down icon-chevron-down', @@ -319,6 +364,10 @@ detailClose: 'glyphicon-minus icon-minus' }, + customSearch: $.noop, + + customSort: $.noop, + rowStyle: function (row, index) { return {}; }, @@ -327,6 +376,10 @@ return {}; }, + footerStyle: function (row, index) { + return {}; + }, + onAll: function (name, args) { return false; }, @@ -399,19 +452,22 @@ onRefreshOptions: function (options) { return false; }, + onRefresh: function (params) { + return false; + }, onResetView: function () { return false; } }; - BootstrapTable.LOCALES = []; + BootstrapTable.LOCALES = {}; - BootstrapTable.LOCALES['en-US'] = BootstrapTable.LOCALES['en'] = { + BootstrapTable.LOCALES['en-US'] = BootstrapTable.LOCALES.en = { formatLoadingMessage: function () { return 'Loading, please wait...'; }, formatRecordsPerPage: function (pageNumber) { - return sprintf('%s records per page', pageNumber); + return sprintf('%s rows per page', pageNumber); }, formatShowingRows: function (pageFrom, pageTo, totalRows) { return sprintf('Showing %s to %s of %s rows', pageFrom, pageTo, totalRows); @@ -470,7 +526,8 @@ cellStyle: undefined, searchable: true, searchFormatter: true, - cardVisible: true + cardVisible: true, + escape : false }; BootstrapTable.EVENTS = { @@ -498,7 +555,8 @@ 'expand-row.bs.table': 'onExpandRow', 'collapse-row.bs.table': 'onCollapseRow', 'refresh-options.bs.table': 'onRefreshOptions', - 'reset-view.bs.table': 'onResetView' + 'reset-view.bs.table': 'onResetView', + 'refresh.bs.table': 'onRefresh' }; BootstrapTable.prototype.init = function () { @@ -507,6 +565,7 @@ this.initTable(); this.initHeader(); this.initData(); + this.initHiddenRows(); this.initFooter(); this.initToolbar(); this.initPagination(); @@ -519,7 +578,7 @@ if (this.options.locale) { var parts = this.options.locale.split(/-|_/); parts[0].toLowerCase(); - parts[1] && parts[1].toUpperCase(); + if (parts[1]) parts[1].toUpperCase(); if ($.fn.bootstrapTable.locales[this.options.locale]) { // locale as requested $.extend(this.options, $.fn.bootstrapTable.locales[this.options.locale]); @@ -589,6 +648,10 @@ var column = []; $(this).find('th').each(function () { + // Fix #2014 - getFieldIndex and elsewhere assume this is string, causes issues if not + if (typeof $(this).data('field') !== 'undefined') { + $(this).data('field', $(this).data('field') + ''); + } column.push($.extend({}, { title: $(this).html(), 'class': $(this).attr('class'), @@ -623,7 +686,8 @@ return; } - this.$el.find('>tbody>tr').each(function () { + var m = []; + this.$el.find('>tbody>tr').each(function (y) { var row = {}; // save tr's id, class and data-* attributes @@ -631,20 +695,38 @@ row._class = $(this).attr('class'); row._data = getRealDataAttr($(this).data()); - $(this).find('td').each(function (i) { - var field = that.columns[i].field; + $(this).find('>td').each(function (x) { + var $this = $(this), + cspan = +$this.attr('colspan') || 1, + rspan = +$this.attr('rowspan') || 1, + tx, ty; + + for (; m[y] && m[y][x]; x++); //skip already occupied cells in current row + + for (tx = x; tx < x + cspan; tx++) { //mark matrix elements occupied by current cell with true + for (ty = y; ty < y + rspan; ty++) { + if (!m[ty]) { //fill missing rows + m[ty] = []; + } + m[ty][tx] = true; + } + } + + var field = that.columns[x].field; row[field] = $(this).html(); // save td's id, class and data-* attributes row['_' + field + '_id'] = $(this).attr('id'); row['_' + field + '_class'] = $(this).attr('class'); row['_' + field + '_rowspan'] = $(this).attr('rowspan'); + row['_' + field + '_colspan'] = $(this).attr('colspan'); row['_' + field + '_title'] = $(this).attr('title'); row['_' + field + '_data'] = getRealDataAttr($(this).data()); }); data.push(row); }); this.options.data = data; + if (data.length) this.fromHtml = true; }; BootstrapTable.prototype.initHeader = function () { @@ -667,8 +749,8 @@ $.each(this.options.columns, function (i, columns) { html.push(''); - if (i == 0 && !that.options.cardView && that.options.detailView) { - html.push(sprintf('
', + if (i === 0 && !that.options.cardView && that.options.detailView) { + html.push(sprintf('
', that.options.columns.length)); } @@ -721,7 +803,7 @@ visibleColumns[column.field] = column; } - html.push(''); html.push(sprintf('
', that.options.sortable && column.sortable ? 'sortable both' : '')); - text = column.title; + text = that.options.escape ? escapeHTML(column.title) : column.title; if (column.checkbox) { if (!that.options.singleSelect && that.options.checkboxHeader) { - text = ''; + text = ''; } that.header.stateField = column.field; } @@ -763,7 +844,14 @@ $(this).data(visibleColumns[$(this).data('field')]); }); this.$container.off('click', '.th-inner').on('click', '.th-inner', function (event) { - if (that.options.sortable && $(this).parent().data().sortable) { + var target = $(this); + + if (that.options.detailView) { + if (target.closest('.bootstrap-table')[0] !== that.$container[0]) + return false; + } + + if (that.options.sortable && target.parent().data().sortable) { that.onSort(event); } }); @@ -777,6 +865,7 @@ } }); + $(window).off('resize.bootstrap-table'); if (!this.options.showHeader || this.options.cardView) { this.$header.hide(); this.$tableHeader.hide(); @@ -787,15 +876,15 @@ this.$tableLoading.css('top', this.$header.outerHeight() + 1); // Assign the correct sortable arrow this.getCaret(); + $(window).on('resize.bootstrap-table', $.proxy(this.resetWidth, this)); } this.$selectAll = this.$header.find('[name="btSelectAll"]'); - this.$container.off('click', '[name="btSelectAll"]') - .on('click', '[name="btSelectAll"]', function () { - var checked = $(this).prop('checked'); - that[checked ? 'checkAll' : 'uncheckAll'](); - that.updateSelected(); - }); + this.$selectAll.off('click').on('click', function () { + var checked = $(this).prop('checked'); + that[checked ? 'checkAll' : 'uncheckAll'](); + that.updateSelected(); + }); }; BootstrapTable.prototype.initFooter = function () { @@ -838,15 +927,27 @@ var that = this, name = this.options.sortName, order = this.options.sortOrder === 'desc' ? -1 : 1, - index = $.inArray(this.options.sortName, this.header.fields); + index = $.inArray(this.options.sortName, this.header.fields), + timeoutId = 0; + + if (this.options.customSort !== $.noop) { + this.options.customSort.apply(this, [this.options.sortName, this.options.sortOrder]); + return; + } if (index !== -1) { + if (this.options.sortStable) { + $.each(this.data, function (i, row) { + if (!row.hasOwnProperty('_position')) row._position = i; + }); + } + this.data.sort(function (a, b) { if (that.header.sortNames[index]) { name = that.header.sortNames[index]; } - var aa = getItemField(a, name), - bb = getItemField(b, name), + var aa = getItemField(a, name, that.options.escape), + bb = getItemField(b, name, that.options.escape), value = calculateObjectValue(that.header, that.header.sorters[index], [aa, bb]); if (value !== undefined) { @@ -861,6 +962,11 @@ bb = ''; } + if (that.options.sortStable && aa === bb) { + aa = a._position; + bb = b._position; + } + // IF both values are numeric, do a numeric comparison if ($.isNumeric(aa) && $.isNumeric(bb)) { // Convert numerical values form string to float. @@ -887,6 +993,17 @@ return order; }); + + if (this.options.sortClass !== undefined) { + clearTimeout(timeoutId); + timeoutId = setTimeout(function () { + that.$el.removeClass(that.options.sortClass); + var index = that.$header.find(sprintf('[data-field="%s"]', + that.options.sortName).index() + 1); + that.$el.find(sprintf('tr td:nth-child(%s)', index)) + .addClass(that.options.sortClass); + }, 250); + } } }; @@ -926,10 +1043,13 @@ $search, switchableCount = 0; + if (this.$toolbar.find('.bs-bars').children().length) { + $('body').append($(this.options.toolbar)); + } this.$toolbar.html(''); if (typeof this.options.toolbar === 'string' || typeof this.options.toolbar === 'object') { - $(sprintf('
', this.options.toolbarAlign)) + $(sprintf('
', this.options.toolbarAlign)) .appendTo(this.$toolbar) .append($(this.options.toolbar)); } @@ -943,37 +1063,44 @@ } if (this.options.showPaginationSwitch) { - html.push(sprintf(''); } if (this.options.showRefresh) { - html.push(sprintf(''); } if (this.options.showToggle) { - html.push(sprintf(''); } if (this.options.showColumns) { html.push(sprintf('
', - this.options.formatColumns()), - '', '
'); - // Fix #188: this.showToolbar is for extentions + // Fix #188: this.showToolbar is for extensions if (this.showToolbar || html.length > 2) { this.$toolbar.append(html.join('')); } @@ -1020,8 +1147,8 @@ if (this.options.showToggle) { this.$toolbar.find('button[name="toggle"]') .off('click').on('click', function () { - that.toggleView(); - }); + that.toggleView(); + }); } if (this.options.showColumns) { @@ -1037,8 +1164,7 @@ $keepOpen.find('input').off('click').on('click', function () { var $this = $(this); - that.toggleColumn(getFieldIndex(that.columns, - $(this).data('field')), $this.prop('checked'), false); + that.toggleColumn($(this).val(), $this.prop('checked'), false); that.trigger('column-switch', $(this).data('field'), $this.prop('checked')); }); } @@ -1047,7 +1173,7 @@ html = []; html.push( '