Merge branch 'develop' into v5-master-develop-integration

# Conflicts:
#	.env.example
#	.travis.yml
#	Dockerfile
#	README.md
#	app/Console/Commands/LdapSync.php
#	app/Console/Kernel.php
#	app/Http/Controllers/AccessoriesController.php
#	app/Http/Controllers/Api/AccessoriesController.php
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Controllers/Api/LocationsController.php
#	app/Http/Controllers/Api/SettingsController.php
#	app/Http/Controllers/Api/UsersController.php
#	app/Http/Controllers/AssetModelsController.php
#	app/Http/Controllers/Assets/AssetFilesController.php
#	app/Http/Controllers/Assets/AssetsController.php
#	app/Http/Controllers/CategoriesController.php
#	app/Http/Controllers/CompaniesController.php
#	app/Http/Controllers/ComponentsController.php
#	app/Http/Controllers/ConsumablesController.php
#	app/Http/Controllers/DepartmentsController.php
#	app/Http/Controllers/LicensesController.php
#	app/Http/Controllers/LocationsController.php
#	app/Http/Controllers/ManufacturersController.php
#	app/Http/Controllers/ReportsController.php
#	app/Http/Controllers/SettingsController.php
#	app/Http/Controllers/SuppliersController.php
#	app/Http/Controllers/UsersController.php
#	app/Http/Middleware/EncryptCookies.php
#	app/Http/Requests/AssetRequest.php
#	app/Http/Transformers/AssetMaintenancesTransformer.php
#	app/Importer/AssetImporter.php
#	app/Models/AssetMaintenance.php
#	app/Models/Location.php
#	app/Models/User.php
#	composer.json
#	composer.lock
#	config/backup.php
#	config/database.php
#	config/version.php
#	public/mix-manifest.json
#	resources/lang/en-ID/general.php
#	resources/lang/vi/admin/settings/general.php
#	resources/views/accessories/edit.blade.php
#	resources/views/hardware/view.blade.php
#	resources/views/layouts/default.blade.php
#	tests/api/ApiCategoriesCest.php
This commit is contained in:
snipe 2019-11-18 19:49:39 -08:00
commit 5290c47e2a
1770 changed files with 23310 additions and 135881 deletions

View file

@ -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",

View file

@ -1,5 +1,13 @@
.git
.github
.gitattributes
.gitignore
.dockerignore
app/storage/logs/*
app/storage/views/*
vendor/*
storage/framework/cache/*
node_modules
.vagrant
.idea

View file

@ -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
# --------------------------------------------

View file

@ -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
# --------------------------------------------

4
.github/autolabeler.yml vendored Normal file
View file

@ -0,0 +1,4 @@
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*"]
backend: ["/app", "*.php"]
legal: ["LICENSE*", "NOTICES*"]
config: .github

33
.github/config.yml vendored Normal file
View file

@ -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 #<issue number>: don't overwrite prevent_default if default wasn't prevented`
- `Added #<issue number>: 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! 🎉🎉🎉

7
.github/weekly-digest.yml vendored Normal file
View file

@ -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

9
.gitignore vendored
View file

@ -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

View file

@ -14,13 +14,11 @@ services:
# list any PHP version you want to test against
php:
- 7.1.2
- 7.1.3
- 7.1.4
- 7.2
- 7.3
- 7.3.0
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 +29,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

View file

@ -1,36 +1,59 @@
FROM ubuntu:xenial
LABEL maintainer="uberbrady, hinchk"
FROM ubuntu:bionic
LABEL maintainer Brady Wetherington <uberbrady@gmail.com>
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 #################

80
Dockerfile.alpine Normal file
View file

@ -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

View file

@ -68,6 +68,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.
@ -106,15 +115,10 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars0.githubusercontent.com/u/1680266?v=4" width="110px;"/><br /><sub>saymd</sub>](https://github.com/saymd)<br />[🌍](#translation-saymd "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1826808?v=4" width="110px;"/><br /><sub>Patrik Larsson</sub>](https://nordsken.se)<br />[🌍](#translation-pooot "Translation") | [<img src="https://avatars1.githubusercontent.com/u/20584746?v=4" width="110px;"/><br /><sub>drcryo</sub>](https://github.com/drcryo)<br />[🌍](#translation-drcryo "Translation") | [<img src="https://avatars1.githubusercontent.com/u/19408004?v=4" width="110px;"/><br /><sub>pawel1615</sub>](https://github.com/pawel1615)<br />[🌍](#translation-pawel1615 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/23340468?v=4" width="110px;"/><br /><sub>bodrovics</sub>](https://github.com/bodrovics)<br />[🌍](#translation-bodrovics "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3257654?v=4" width="110px;"/><br /><sub>priatna</sub>](https://github.com/priatna)<br />[🌍](#translation-priatna "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5358374?v=4" width="110px;"/><br /><sub>Fan Jiang</sub>](https://amayume.net)<br />[🌍](#translation-ProfFan "Translation") |
| [<img src="https://avatars1.githubusercontent.com/u/22555451?v=4" width="110px;"/><br /><sub>ragnarcx</sub>](https://github.com/ragnarcx)<br />[🌍](#translation-ragnarcx "Translation") | [<img src="https://avatars2.githubusercontent.com/u/18654582?v=4" width="110px;"/><br /><sub>Rein van Haaren</sub>](http://www.reinvanhaaren.nl/)<br />[🌍](#translation-reinvanhaaren "Translation") | [<img src="https://avatars1.githubusercontent.com/u/386672?v=4" width="110px;"/><br /><sub>Teguh Dwicaksana</sub>](http://dheche.songolimo.net)<br />[🌍](#translation-dheche "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2572552?v=4" width="110px;"/><br /><sub>fraccie</sub>](https://github.com/FRaccie)<br />[🌍](#translation-FRaccie "Translation") | [<img src="https://avatars0.githubusercontent.com/u/35182720?v=4" width="110px;"/><br /><sub>vinzruzell</sub>](https://github.com/vinzruzell)<br />[🌍](#translation-vinzruzell "Translation") | [<img src="https://avatars1.githubusercontent.com/u/7883603?v=4" width="110px;"/><br /><sub>Kevin Austin</sub>](http://kevinaustin.com)<br />[🌍](#translation-vipsystem "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3861828?v=4" width="110px;"/><br /><sub>Wira Sandy</sub>](http://azuraweb.xyz)<br />[🌍](#translation-wira-sandy "Translation") |
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [<img src="https://avatars0.githubusercontent.com/u/17459600?v=4" width="110px;"/><br /><sub>Marián Skrip</sub>](https://github.com/mskrip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/2611616?v=4" width="110px;"/><br /><sub>Dmitriy Minaev</sub>](https://github.com/VELIKII-DIVAN)<br />[💻](https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN "Code") | [<img src="https://avatars0.githubusercontent.com/u/5132245?v=4" width="110px;"/><br /><sub>liquidhorse</sub>](https://github.com/liquidhorse)<br />[💻](https://github.com/snipe/snipe-it/commits?author=liquidhorse "Code") | [<img src="https://avatars1.githubusercontent.com/u/183678?v=4" width="110px;"/><br /><sub>Jordi Boggiano</sub>](https://seld.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Seldaek "Code") | [<img src="https://avatars0.githubusercontent.com/u/653557?v=4" width="110px;"/><br /><sub>Ivan Nieto</sub>](https://github.com/inietov)<br />[💻](https://github.com/snipe/snipe-it/commits?author=inietov "Code") | [<img src="https://avatars2.githubusercontent.com/u/6764151?v=4" width="110px;"/><br /><sub>Ben RUBSON</sub>](https://github.com/benrubson)<br />[💻](https://github.com/snipe/snipe-it/commits?author=benrubson "Code") | [<img src="https://avatars2.githubusercontent.com/u/8554558?v=4" width="110px;"/><br /><sub>NMathar</sub>](https://github.com/NMathar)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NMathar "Code") | [<img src="https://avatars1.githubusercontent.com/u/139566?v=4" width="110px;"/><br /><sub>Steffen</sub>](https://github.com/smb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=smb "Code") |
| [<img src="https://avatars0.githubusercontent.com/u/6609453?v=4" width="110px;"/><br /><sub>Sxderp</sub>](https://github.com/Sxderp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Sxderp "Code") | [<img src="https://avatars1.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>fanta8897</sub>](https://github.com/fanta8897)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fanta8897 "Code") | [<img src="https://avatars2.githubusercontent.com/u/2576509?v=4" width="110px;"/><br /><sub>Andrey Bolonin</sub>](https://andreybolonin.com/phpconsulting/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreybolonin "Code") | [<img src="https://avatars3.githubusercontent.com/u/2173307?v=4" width="110px;"/><br /><sub>shinayoshi</sub>](http://www.shinayoshi.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=shinayoshi "Code") | [<img src="https://avatars3.githubusercontent.com/u/2130159?v=4" width="110px;"/><br /><sub>Hubert</sub>](https://github.com/reuser)<br />[💻](https://github.com/snipe/snipe-it/commits?author=reuser "Code") | [<img src="https://avatars0.githubusercontent.com/u/6865789?v=4" width="110px;"/><br /><sub>KeenRivals</sub>](https://brashear.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KeenRivals "Code") | [<img src="https://avatars3.githubusercontent.com/u/2902513?v=4" width="110px;"/><br /><sub>omyno</sub>](https://github.com/omyno)<br />[💻](https://github.com/snipe/snipe-it/commits?author=omyno "Code") |
| [<img src="https://avatars1.githubusercontent.com/u/6271335?v=4" width="110px;"/><br /><sub>Evgeny</sub>](https://github.com/jackka)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jackka "Code") | [<img src="https://avatars2.githubusercontent.com/u/1169963?v=4" width="110px;"/><br /><sub>Colin Campbell</sub>](https://digitalist.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=colin-campbell "Code") | [<img src="https://avatars3.githubusercontent.com/u/2872098?v=4" width="110px;"/><br /><sub>Ľubomír Kučera</sub>](https://github.com/lubo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lubo "Code") | [<img src="https://avatars3.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://www.sourceguru.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Mezzle "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
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.

18
Vagrantfile vendored
View file

@ -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

View file

@ -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: |
<VirtualHost *>
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
<Directory /usr/local/www/apache24/data/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
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

View file

@ -76,10 +76,4 @@ class CreateAdmin extends Command
}
// protected function getArguments()
// {
// return array(
// array('username', InputArgument::REQUIRED, 'Username'),
// );
// }
}

View file

@ -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.');

View file

@ -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]++;

View file

@ -0,0 +1,183 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class MoveUploadsToNewDisk extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:move-uploads {delete_local?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This will move your uploaded files to whatever your current disk is.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (config('filesystems.default')=='local') {
$this->error('Your current disk is set to local so we cannot proceed.');
$this->warn("Please configure your .env settings for S3 or Rackspace, \nand change your FILESYSTEM_DISK value to 's3' or 'rackspace'.");
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['barcodes'] = glob('storage/app/public/barcodes'."/*.*");
$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'."/logo*.*");
$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'."/*.*");
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 delete from your filesystem.");
}
}
}
}

View file

@ -1,31 +1,9 @@
<?php
namespace App\Console\Commands;
use App\Helpers\Helper;
use App\Importer\AccessoryImporter;
use App\Importer\AssetImporter;
use App\Importer\ConsumableImporter;
use App\Importer\Importer;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\CustomField;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use DB;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use League\Csv\Reader;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use ForceUTF8\Encoding;
ini_set('max_execution_time', 600); //600 seconds = 10 minutes
ini_set('memory_limit', '500M');

View file

@ -2,22 +2,19 @@
namespace App\Console\Commands;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\License;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Console\Command;
use DB;
use \App\Models\Asset;
use \App\Models\AssetModel;
use \App\Models\Location;
use \App\Models\Company;
use \App\Models\License;
use \App\Models\Accessory;
use \App\Models\Component;
use \App\Models\Consumable;
use \App\Models\Category;
use \App\Models\User;
use \App\Models\Supplier;
use \App\Models\Manufacturer;
use \App\Models\Depreciation;
use \App\Models\Statuslabel;
class Purge extends Command
{

View file

@ -2,11 +2,11 @@
namespace App\Console\Commands;
use App\Models\CustomField;
use Illuminate\Console\Command;
use App\LegacyEncrypter\McryptEncrypter;
use App\Models\Setting;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\Setting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class RecryptFromMcrypt extends Command

View file

@ -2,11 +2,10 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Asset;
use App\Models\Setting;
use DB;
use Artisan;
use Illuminate\Console\Command;
class RegenerateAssetTags extends Command
{

View file

@ -3,9 +3,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Console\Command;
class ResetDemoSettings extends Command
{

View file

@ -2,16 +2,13 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\User;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Consumable;
use App\Models\Accessory;
use App\Models\LicenseSeat;
use App\Models\License;
use DB;
use App\Models\User;
use Artisan;
use DB;
use Illuminate\Console\Command;
class RestoreDeletedUsers extends Command
{

View file

@ -0,0 +1,60 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Notifications\CurrentInventory;
use Illuminate\Console\Command;
class SendCurrentInventoryToUsers extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:user-inventory';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This will send users a report of all of the items currently checked out to them.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$users = User::whereNull('deleted_at')->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.');
}
}

View file

@ -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));
}
}
}

View file

@ -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');
}
}
}
}

View file

@ -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');
}
}
}
}

View file

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Asset;
use Illuminate\Console\Command;
class SyncAssetCounters extends Command
{

View file

@ -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
{

View file

@ -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');

View file

@ -0,0 +1,23 @@
<?php
namespace App\Events;
use App\Models\CheckoutAcceptance;
use App\Models\Contracts\Acceptable;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CheckoutAccepted
{
use Dispatchable, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(CheckoutAcceptance $acceptance)
{
$this->acceptance = $acceptance;
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace App\Events;
use App\Models\CheckoutAcceptance;
use App\Models\Contracts\Acceptable;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CheckoutDeclined
{
use Dispatchable, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(CheckoutAcceptance $acceptance)
{
$this->acceptance = $acceptance;
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CheckoutableCheckedIn
{
use Dispatchable, SerializesModels;
public $checkoutable;
public $checkedOutTo;
public $checkedInBy;
public $note;
public $action_date; // Date setted in the hardware.checkin view at the checkin_at input, for the action log
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note, $action_date)
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedInBy = $checkedInBy;
$this->note = $note;
$this->action_date = $action_date;
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CheckoutableCheckedOut
{
use Dispatchable, SerializesModels;
public $checkoutable;
public $checkedOutTo;
public $checkedOutBy;
public $note;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note)
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedOutBy = $checkedOutBy;
$this->note = $note;
}
}

View file

@ -3,6 +3,7 @@
namespace App\Exceptions;
use Exception;
class CheckoutNotAllowed extends Exception
{

View file

@ -9,6 +9,7 @@ use App\Helpers\Helper;
use Illuminate\Validation\ValidationException;
use Log;
class Handler extends ExceptionHandler
{
/**

View file

@ -1,25 +1,16 @@
<?php
namespace App\Helpers;
use DB;
use App\Models\Statuslabel;
use App\Models\Location;
use App\Models\Department;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\User;
use App\Models\Manufacturer;
use App\Models\Supplier;
use App\Models\Category;
use App\Models\Depreciation;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use App\Models\Component;
use App\Models\Accessory;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use App\Models\Depreciation;
use App\Models\Setting;
use App\Models\Statuslabel;
use Crypt;
use Image;
use Illuminate\Contracts\Encryption\DecryptException;
class Helper
@ -225,8 +216,9 @@ class Helper
*/
public static function predefined_formats()
{
$keys = array_keys(CustomField::$PredefinedFormats);
$keys = array_keys(CustomField::PREDEFINED_FORMATS);
$stuff = array_combine($keys, $keys);
return $stuff;
}
@ -669,7 +661,80 @@ class Helper
return false;
}
/**
* Generate a random encrypted password.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @return string
*/
public static function generateEncyrptedPassword(): string
{
return bcrypt(Helper::generateUnencryptedPassword());
}
/**
* Get a random unencrypted password.
*
* @author Steffen Buehl <sb@sbuehl.com>
*
* @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;
}
}

View file

@ -0,0 +1,207 @@
<?php
namespace App\Http\Controllers\Accessories;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Accessory;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Redirect;
/** This controller handles all actions related to Accessories for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class AccessoriesController extends Controller
{
/**
* 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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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]));
}
}

View file

@ -0,0 +1,78 @@
<?php
namespace App\Http\Controllers\Accessories;
use App\Events\CheckoutableCheckedIn;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class AccessoryCheckinController extends Controller
{
/**
* Check the accessory back into inventory
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace App\Http\Controllers\Accessories;
use App\Events\CheckoutableCheckedOut;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Input;
class AccessoryCheckoutController extends Controller
{
/**
* Return the form to checkout an Accessory to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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(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')
]);
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'));
}
}

View file

@ -1,400 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Auth;
use Carbon\Carbon;
use Config;
use DB;
use Gate;
use Input;
use Lang;
use Redirect;
use Illuminate\Http\Request;
use Slack;
use Str;
use View;
use Image;
use App\Http\Requests\ImageUploadRequest;
/** This controller handles all actions related to Accessories for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class AccessoriesController extends Controller
{
/**
* 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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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');
if ($request->hasFile('image')) {
if (!config('app.lock_passwords')) {
$image = $request->file('image');
$ext = $image->getClientOriginalExtension();
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
$accessory->image = $file_name;
}
}
// 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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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');
if ($request->hasFile('image')) {
if (!config('app.lock_passwords')) {
$image = $request->file('image');
$ext = $image->getClientOriginalExtension();
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
if (($accessory->image) && (file_exists($path.'/'.$accessory->image))) {
unlink($path.'/'.$accessory->image);
}
$accessory->image = $file_name;
}
}
// 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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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', compact('id')));
}
/**
* Return the form to checkout an Accessory to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -0,0 +1,127 @@
<?php
namespace App\Http\Controllers\Account;
use App\Events\CheckoutAccepted;
use App\Events\CheckoutDeclined;
use App\Events\ItemAccepted;
use App\Events\ItemDeclined;
use App\Http\Controllers\Controller;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\Contracts\Acceptable;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class AcceptanceController extends Controller {
/**
* Show a listing of pending checkout acceptances for the current user
*
* @return View
*/
public function index() {
$acceptances = CheckoutAcceptance::forUser(Auth::user())->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);
}
}

View file

@ -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
{
@ -139,18 +140,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);
}
@ -165,7 +185,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());
@ -288,4 +308,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);
}
}

View file

@ -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')) {

View file

@ -1,15 +1,15 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\AssetModel;
use App\Models\Asset;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Transformers\AssetModelsTransformer;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Asset;
use App\Models\AssetModel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
/**
* This class controls all actions related to asset models for
@ -180,7 +180,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);
}
@ -237,7 +237,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('assetmodels/'.e($assetmodel->image)) : null;
}
return (new SelectlistTransformer)->transformSelectlist($assetmodels);

View file

@ -1,38 +1,31 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Support\Facades\Gate;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetRequest;
use App\Http\Requests\AssetCheckoutRequest;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\CustomField;
use App\Models\License;
use App\Models\Location;
use App\Models\Setting;
use App\Models\User;
use Artisan;
use Auth;
use Carbon\Carbon;
use Config;
use DB;
use Gate;
use Illuminate\Http\Request;
use Input;
use Lang;
use Log;
use Mail;
use Paginator;
use Response;
use Slack;
use Str;
use TCPDF;
use Validator;
use View;
use App\Http\Transformers\SelectlistTransformer;
/**
* This class controls all actions related to assets for
@ -173,7 +166,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) {
@ -288,9 +281,9 @@ class AssetsController extends Controller
break;
}
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
// dd($assets);
return (new AssetsTransformer)->transformAssets($assets, $total);
}
@ -305,7 +298,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);
}
@ -326,8 +319,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);
@ -344,14 +336,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());
}
/**
* Gets a paginated collection for the select2 menus
@ -372,7 +372,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();
@ -418,7 +418,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);
@ -446,6 +446,22 @@ class AssetsController extends Controller
$asset->requestable = $request->get('requestable', 0);
$asset->rtd_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'));
@ -473,6 +489,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')));
}
@ -493,15 +514,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))) {
@ -522,9 +568,9 @@ 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;
$location = $target->location_id;
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
$location = $target->id;
}
@ -533,6 +579,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);
@ -724,13 +774,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()) {
@ -738,7 +802,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')));
}
}

View file

@ -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
{
@ -117,15 +118,15 @@ class CategoriesController extends Controller
public function destroy($id)
{
$this->authorize('delete', Category::class);
$category = Category::findOrFail($id);
$category = Category::withCount('models as models_count', 'accessories as accessories_count','consumables as consumables_count','components as components_count')->findOrFail($id);
if ($category->has_models() > 0) {
if ($category->models_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'model'])));
} elseif ($category->accessories()->count() > 0) {
} 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) {
} 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) {
} elseif ($category->components_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'component'])));
}
$category->delete();
@ -161,7 +162,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);

View file

@ -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
{
@ -181,7 +182,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);

View file

@ -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
{

View file

@ -2,12 +2,13 @@
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\Http\Transformers\ConsumablesTransformer;
use App\Helpers\Helper;
use Illuminate\Http\Request;
class ConsumablesController extends Controller
{
@ -159,7 +160,7 @@ class ConsumablesController extends Controller
* Returns a JSON response containing details on the users associated with this consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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
@ -194,4 +195,28 @@ class ConsumablesController extends Controller
$data = array('total' => $consumableCount, 'rows' => $rows);
return $data;
}
/**
* 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);
}
}

View file

@ -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
*/

View file

@ -1,22 +1,14 @@
<?php
namespace App\Http\Controllers\Api;
use View;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use Input;
use Validator;
use Redirect;
use App\Models\AssetModel;
use Lang;
use Auth;
use Illuminate\Http\Request;
use Log;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Http\Transformers\CustomFieldsTransformer;
use App\Http\Controllers\Controller;
use App\Http\Transformers\CustomFieldsetsTransformer;
use App\Http\Requests\AssetRequest;
use App\Http\Transformers\CustomFieldsTransformer;
use App\Models\CustomFieldset;
use Illuminate\Http\Request;
use Redirect;
use View;
/**
* This controller handles all actions related to Custom Asset Fieldsets for

View file

@ -2,13 +2,14 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Http\Transformers\DepartmentsTransformer;
use App\Helpers\Helper;
use Auth;
use App\Http\Controllers\Controller;
use App\Http\Transformers\DepartmentsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Department;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class DepartmentsController extends Controller
{
@ -103,14 +104,36 @@ class DepartmentsController extends Controller
return (new DepartmentsTransformer)->transformDepartment($department);
}
/**
* Update the specified resource in storage.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @param int $locationId
* @since [v1.0]
* @since [v4.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy($id)
@ -155,7 +178,7 @@ 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);

View file

@ -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
{
@ -113,10 +113,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')));
}

View file

@ -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
{

View file

@ -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 Artisan;
use Illuminate\Support\Facades\Input;
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
{
@ -112,7 +112,7 @@ 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)
@ -155,19 +155,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')));
}
}
}
}

View file

@ -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;
@ -153,7 +154,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);
}
@ -233,9 +234,14 @@ class LicensesController extends Controller
$offset = (($seats) && (request('offset') > $seats->count())) ? 0 : request('offset', 0);
$limit = request('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$total = $seats->count();
if($total < $offset){
$offset = 0;
}
$seats = $seats->skip($offset)->take($limit)->get();
if ($seats) {
@ -248,5 +254,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);
}
}

View file

@ -2,14 +2,15 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Location;
use App\Http\Controllers\Controller;
use App\Http\Transformers\LocationsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Location;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class LocationsController extends Controller
{
@ -240,8 +241,8 @@ class LocationsController extends Controller
$locations_with_children = [];
foreach ($locations as $location) {
if(!array_key_exists($location->parent_id, $locations_with_children)) {
$locations_with_children[$location->parent_id] = [];
$location->use_text = $location->name;
$location->use_image = ($location->image) ? Storage::disk('public')->url('locations/'.$location->image, $location->image): null;
}
$locations_with_children[$location->parent_id][] = $location;
}

View file

@ -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);
$manufacturer = Manufacturer::withCount('assets as assets_count', 'licenses as licenses_count', 'consumables as consumables_count', 'accessories as accessories_count', 'models as models_count' )->findOrFail($id);
$this->authorize('delete', $manufacturer);
$manufacturer->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success')));
if (($manufacturer->assets_count == 0) && ($manufacturer->licenses_count==0) && ($manufacturer->consumables_count==0) && ($manufacturer->accessories_count==0) && ($manufacturer->models_count==0) && ($manufacturer->deleted_at=='')) {
$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.delete.error')));
}
@ -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);

View file

@ -0,0 +1,449 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\PredefinedKitsTransformer;
use App\Models\PredefinedKit;
use Illuminate\Http\Request;
/**
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
*/
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
}
}

View file

@ -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
{

View file

@ -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
{

View file

@ -2,104 +2,88 @@
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\Notifications\SlackTest;
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;
class SettingsController extends Controller
{
public function ldaptest()
/**
* Test the ldap settings
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @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 cannot test.');
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) {
\Log::debug('Bind failed');
return response()->json(['message' => $e->getMessage()], 400);
//return response()->json(['message' => $e->getMessage()], 500);
$ldap->testLdapAdUserConnection();
$message['login'] = [
'message' => 'Successfully connected to LDAP server.'
];
} catch (\Exception $ex) {
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::debug('Connection failed but we cannot debug it any further on our end.');
return response()->json(['message' => $e->getMessage()], 600);
], 400);
}
}
public function ldaptestlogin(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);
}
$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');
Log::info('Preparing to test LDAP bind connection');
// Test user can bind to the LDAP server
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);
$ldap->testLdapAdBindConnection();
$message['bind'] = [
'message' => 'Successfully binded to LDAP server.'
];
} catch (\Exception $ex) {
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 {
$users = $ldap->testUserImportSync();
$message['user_sync'] = [
'users' => $users
];
} catch (\Exception $ex) {
$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 slacktest()
{
@ -143,6 +127,30 @@ class SettingsController extends Controller
}
/**
* Get a list of login attempts
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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);
}
}

View file

@ -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
{
@ -207,11 +207,11 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$this->authorize('index', Asset::class);
$assets = Asset::where('status_id','=',$id);
$assets = Asset::where('status_id','=',$id)->with('assignedTo');
$allowed_columns = [
'id',
'name'
'name',
];
$offset = request('offset', 0);
@ -241,8 +241,6 @@ class StatuslabelsController extends Controller
*/
public function checkIfDeployable($id) {
$statuslabel = Statuslabel::findOrFail($id);
$this->authorize('view', Asset::class);
if ($statuslabel->getStatuslabelType()=='deployable') {
return '1';
}

View file

@ -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')
@ -167,7 +167,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);

View file

@ -2,17 +2,19 @@
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 Illuminate\Http\Request;
class UsersController extends Controller
{
@ -206,6 +208,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'));
@ -247,6 +250,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')) {
@ -315,8 +328,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')));
@ -356,6 +377,26 @@ class UsersController extends Controller
}
/**
* Return JSON containing a list of licenses assigned to a user.
*
* @author [N. Mathar] [<snipe@snipe.net>]
* @since [v5.0]
* @param $userId
* @return string JSON
*/
public function licenses($id)
{
$this->authorize('view', User::class);
$this->authorize('view', License::class);
$user = User::where('id', $id)->withTrashed()->first();
$licenses = $user->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
}
/**
* Reset the user's two-factor status
*
* @author [A. Gianotto] [<snipe@snipe.net>]

View file

@ -1,26 +1,17 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use Carbon\Carbon;
use App\Models\Company;
use DB;
use Input;
use Lang;
use Log;
use Mail;
use Response;
use Auth;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Slack;
use Str;
use TCPDF;
use Validator;
use View;
use App\Models\Setting;
use App\Models\Asset;
use App\Helpers\Helper;
use Auth;
use Gate;
use Illuminate\Http\Request;
/**
* This controller handles all actions related to Asset Maintenance for
@ -165,6 +156,7 @@ class AssetMaintenancesController extends Controller
} elseif (!$assetMaintenance->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();
}

View file

@ -1,25 +1,13 @@
<?php
namespace App\Http\Controllers;
use App\Models\CustomField;
use Image;
use Input;
use Lang;
use App\Models\AssetModel;
use Redirect;
use Auth;
use DB;
use Str;
use Validator;
use View;
use App\Models\Asset;
use App\Models\Company;
use Config;
use App\Helpers\Helper;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Models\AssetModel;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\View;
use Redirect;
/**
* This class controls all actions related to asset models for
@ -31,13 +19,14 @@ use Symfony\Component\HttpFoundation\JsonResponse;
class AssetModelsController extends Controller
{
/**
* 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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function index()
{
$this->authorize('index', AssetModel::class);
@ -45,29 +34,31 @@ class AssetModelsController extends Controller
}
/**
* Returns a view containing the asset model creation form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
* Returns a view containing the asset model creation form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @since [v1.0]
* @return Redirect
*/
* Validate and process the new Asset Model data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param ImageUploadRequest $request
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function store(ImageUploadRequest $request)
{
@ -90,23 +81,7 @@ class AssetModelsController extends Controller
$model->fieldset_id = e($request->input('custom_fieldset'));
}
if (Input::file('image')) {
$image = Input::file('image');
$file_name = str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
$path = app('models_upload_path');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
$model->image = $file_name;
}
$model = $request->handleImages($model);
// Was it created?
if ($model->save()) {
@ -121,13 +96,14 @@ class AssetModelsController extends Controller
}
/**
* Returns a view containing the asset model edit form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
* Returns a view containing the asset model edit form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($modelId = null)
{
$this->authorize('update', AssetModel::class);
@ -144,14 +120,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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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);
@ -182,37 +160,7 @@ class AssetModelsController extends Controller
}
}
$old_image = $model->image;
// Set the model's image property to null if the image is being deleted
if ($request->input('image_delete') == 1) {
$model->image = null;
}
if ($request->file('image')) {
$image = $request->file('image');
$file_name = $model->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('models_upload_path').$file_name);
} else {
$image->move(app('models_upload_path'), $file_name);
}
$model->image = $file_name;
}
if ((($request->file('image')) && (isset($old_image)) && ($old_image!='')) || ($request->input('image_delete') == 1)) {
try {
unlink(app('models_upload_path').$old_image);
} catch (\Exception $e) {
\Log::info($e);
}
}
$model = $request->handleImages($model);
if ($model->save()) {
return redirect()->route("models.index")->with('success', trans('admin/models/message.update.success'));
@ -221,14 +169,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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy($modelId)
{
$this->authorize('delete', AssetModel::class);
@ -244,7 +193,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);
}
@ -259,13 +208,14 @@ class AssetModelsController extends Controller
/**
* Restore a given Asset Model (mark as un-deleted)
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
*/
* Restore a given Asset Model (mark as un-deleted)
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function getRestore($modelId = null)
{
$this->authorize('create', AssetModel::class);
@ -273,16 +223,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'));
@ -290,13 +232,14 @@ class AssetModelsController extends Controller
/**
* Get the model information to present to the model view page
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
* Get the model information to present to the model view page
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($modelId = null)
{
$this->authorize('view', AssetModel::class);
@ -305,11 +248,8 @@ class AssetModelsController extends Controller
if (isset($model->id)) {
return view('models/view', compact('model'));
}
// Prepare the error message
$error = trans('admin/models/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('models.index')->with('error', $error);
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
/**
@ -331,12 +271,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);
}
@ -350,8 +288,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));
}

View file

@ -1,25 +1,29 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Assets;
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckinRequest;
use App\Models\Asset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class AssetCheckinController extends Controller
{
/**
* Returns a view that presents a form to check an asset back into inventory.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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)
@ -77,21 +82,15 @@ 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'));

View file

@ -1,15 +1,14 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Assets;
use App\Exceptions\CheckoutNotAllowed;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckoutRequest;
use App\Models\Asset;
use App\Models\Location;
use App\Models\User;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AssetCheckoutController extends Controller

View file

@ -1,13 +1,14 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Assets;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetFileRequest;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
class AssetFilesController extends Controller
{
@ -19,6 +20,7 @@ class AssetFilesController extends Controller
* @param int $assetId
* @return Redirect
* @since [v1.0]
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function store(AssetFileRequest $request, $assetId = null)
{
@ -28,15 +30,15 @@ class AssetFilesController extends Controller
$this->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] [<snipe@snipe.net>]
* @param int $assetId
* @param int $fileId
* @since [v1.0]
* @return View
*/
* Check for permissions and display the file.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @param int $assetId
* @param int $fileId
* @since [v1.0]
* @return View
*/
* Delete the associated file
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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

View file

@ -1,44 +1,34 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Assets;
use App\Helpers\Helper;
use App\Http\Requests\AssetCheckinRequest;
use App\Http\Requests\AssetCheckoutRequest;
use App\Http\Requests\AssetFileRequest;
use App\Http\Requests\AssetRequest;
use App\Http\Requests\ItemImportRequest;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\CheckoutRequest;
use App\Models\Company;
use App\Models\CustomField;
use App\Models\Import;
use App\Models\Location;
use App\Models\Setting;
use App\Models\User;
use Artisan;
use Auth;
use Carbon\Carbon;
use Config;
use DB;
use Gate;
use Illuminate\Http\Request;
use Image;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Input;
use Lang;
use League\Csv\Reader;
use Log;
use Mail;
use League\Csv\Statement;
use Paginator;
use Redirect;
use Response;
use Slack;
use Str;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use TCPDF;
use Validator;
use View;
use App\Models\CheckoutRequest;
/**
* This class controls all actions related to assets for
@ -66,7 +56,9 @@ class AssetsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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)
{
@ -110,75 +102,63 @@ 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')));
$success = false;
$serials = $request->input('serials');
$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);
for ($a = 1; $a <= count($asset_tags); $a++) {
if ($asset->assigned_to=='') {
$asset->location_id = $request->input('rtd_location_id', null);
}
$asset = new Asset();
$asset->model()->associate(AssetModel::find($request->input('model_id')));
$asset->name = $request->input('name');
// Check for a corresponding serial
if (($serials) && (array_key_exists($a, $serials))) {
$asset->serial = $serials[$a];
}
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);
if (!empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
}
if ($asset->assigned_to=='') {
$asset->location_id = $request->input('rtd_location_id', null);
}
// Create the image (if one was chosen.)
if ($request->filled('image')) {
$image = $request->input('image');
// 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);
}
$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 ($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'));
@ -195,31 +175,39 @@ class AssetsController extends Controller
}
}
// Was the asset created?
if ($asset->save()) {
// 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'), '', 'Checked out on asset creation', e($request->get('name')), $location);
}
$success = true;
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);
}
// Redirect to the asset listing page
\Session::flash('success', trans('admin/hardware/message.create.success'));
return response()->json(['redirect_url' => route('hardware.index')]);
}
\Input::flash();
\Session::flash('errors', $asset->getErrors());
return response()->json(['errors' => $asset->getErrors()], 500);
if ($success) {
// Redirect to the asset listing page
return redirect()->route('hardware.index')
->with('success', trans('admin/hardware/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($asset->getErrors());
}
/**
@ -297,7 +285,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)) {
@ -333,47 +321,18 @@ class AssetsController extends Controller
// 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
@ -394,13 +353,12 @@ class AssetsController extends Controller
if ($asset->save()) {
// 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()->with('error', trans('admin/hardware/message.does_not_exist'));
}
/**
@ -425,6 +383,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'));
@ -515,6 +481,29 @@ class AssetsController extends Controller
}
}
/**
* Return a label for an individual asset.
*
* @author [L. Swartzendruber] [<logan.swartzendruber@gmail.com>
* @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.
*
@ -554,7 +543,7 @@ class AssetsController extends Controller
*/
public function getImportHistory()
{
$this->authorize('checkout', Asset::class);
$this->authorize('admin');
return view('hardware/history');
}
@ -578,7 +567,6 @@ 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->setHeaderOffset(0);
$results = $csv->getRecords();
@ -586,8 +574,6 @@ class AssetsController extends Controller
$status = array();
$status['error'] = array();
$status['success'] = array();
foreach ($results as $row) {
if (is_array($row)) {
$row = array_change_key_case($row, CASE_LOWER);
@ -596,29 +582,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'];
@ -638,12 +618,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,
@ -654,9 +632,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 {
@ -672,19 +648,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(
@ -703,6 +676,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.
*
@ -763,7 +741,7 @@ class AssetsController extends Controller
}
public function auditStore(AssetFileRequest $request, $id)
public function auditStore(Request $request, $id)
{
$this->authorize('audit', Asset::class);
@ -786,24 +764,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'));
}
}

View file

@ -1,12 +1,12 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Assets;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
@ -14,6 +14,7 @@ use Illuminate\Support\Facades\DB;
class BulkAssetsController extends Controller
{
use CheckInOutRequest;
/**
* Display the bulk edit page.
*
@ -21,6 +22,7 @@ class BulkAssetsController extends Controller
* @return View
* @internal param int $assetId
* @since [v2.0]
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit(Request $request)
{
@ -38,6 +40,7 @@ class BulkAssetsController extends Controller
return view('hardware/labels')
->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);
@ -130,10 +133,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 +151,9 @@ class BulkAssetsController extends Controller
* Save bulk deleted.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
* @internal param array $assets
* @since [v2.0]
*/

View file

@ -49,27 +49,28 @@ class ForgotPasswordController extends Controller
*/
public function sendResetLinkEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$this->validate($request, ['username' => 'required'], ['username.required' => 'Please enter your username.']);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
// Make sure the user is active, and their password is not controlled via LDAP
$response = $this->broker()->sendResetLink(
array_merge(
$request->only('email'),
['activated' => '1']
$request->only('username'),
['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('username').' found, password reset sent');
} else {
\Log::info('Password reset attempt: User '.$request->input('username').' not found or user is inactive');
}
// If an error was returned by the password broker, we will get this message
// translated so we can notify a user of the problem. We'll redirect back
// to where the users came from so they can attempt this process again.
return back()->withErrors(
['email' => trans($response)]
);
// 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'));
}
}

View file

@ -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 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\Input;
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,15 +40,24 @@ class LoginController extends Controller
*/
protected $redirectTo = '/';
/**
* @var LdapAd
*/
protected $ldap;
/**
* Create a new authentication controller instance.
*
* @param LdapAd $ldap
*
* @return void
*/
public function __construct()
public function __construct(LdapAd $ldap)
{
parent::__construct();
$this->middleware('guest', ['except' => ['logout','postTwoFactorAuth','getTwoFactorAuth','getTwoFactorEnroll']]);
\Session::put('backUrl', \URL::previous());
Session::put('backUrl', \URL::previous());
$this->ldap = $ldap;
}
function showLoginForm(Request $request)
@ -64,11 +74,35 @@ class LoginController extends Controller
return view('auth.login');
}
/**
* Log in a user by LDAP
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @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 +119,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.
*
@ -160,9 +147,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 +215,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 +266,8 @@ class LoginController extends Controller
/**
* Two factor code submission
*
* @param Request $request
*
* @return Redirect
*/
public function postTwoFactorAuth(Request $request)
@ -279,11 +281,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,6 +304,8 @@ class LoginController extends Controller
/**
* Logout page.
*
* @param Request $request
*
* @return Redirect
*/
public function logout(Request $request)

View file

@ -3,7 +3,6 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class RegisterController extends Controller
{

View file

@ -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)]);
}
}

View file

@ -0,0 +1,138 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\AssetModel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
class BulkAssetModelsController extends Controller
{
/**
* Returns a view that allows the user to bulk edit model attrbutes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.7]
* @param Request $request
* @return \Illuminate\Contracts\View\View
*/
public function edit(Request $request)
{
$models_raw_array = Input::get('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] [<snipe@snipe.net>]
* @since [v1.7]
* @param Request $request
* @return \Illuminate\Contracts\View\View
*/
public function update(Request $request)
{
$models_raw_array = Input::get('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] [<snipe@snipe.net>]
* @since [v1.0]
* @return Redirect
*/
public function destroy()
{
$models_raw_array = Input::get('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'));
}
}

View file

@ -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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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,17 +76,7 @@ class CategoriesController extends Controller
$category->checkin_email = $request->input('checkin_email', '0');
$category->user_id = Auth::id();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/categories/'.$file_name);
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$category->image = $file_name;
}
$category = $request->handleImages($category);
if ($category->save()) {
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.create.success'));
@ -103,24 +86,23 @@ class CategoriesController extends Controller
}
/**
* Returns a view that makes a form to update a category.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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());
}
@ -129,14 +111,15 @@ class CategoriesController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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'));
@ -151,37 +134,7 @@ class CategoriesController extends Controller
$category->use_default_eula = $request->input('use_default_eula', '0');
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$old_image = $category->image;
// Set the model's image property to null if the image is being deleted
if ($request->input('image_delete') == 1) {
$category->image = null;
}
if ($request->file('image')) {
$image = $request->file('image');
$file_name = $category->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('categories_upload_path').$file_name);
} else {
$image->move(app('categories_upload_path'), $file_name);
}
$category->image = $file_name;
}
if ((($request->file('image')) && (isset($old_image)) && ($old_image!='')) || ($request->input('image_delete') == 1)) {
try {
unlink(app('categories_upload_path').$old_image);
} catch (\Exception $e) {
\Log::info($e);
}
}
$category = $request->handleImages($category);
if ($category->save()) {
@ -193,31 +146,33 @@ class CategoriesController extends Controller
}
/**
* Validates and marks a category as deleted.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $categoryId
* @return \Illuminate\Http\RedirectResponse
* Validates and marks a category as deleted.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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::withCount('models as models_count', 'accessories as accessories_count','consumables as consumables_count','components as components_count')->findOrFail($categoryId))) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
}
if ($category->has_models() > 0) {
if ($category->models_count > 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']));
} 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']));
}
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'));
@ -225,14 +180,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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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)
{
@ -255,10 +211,8 @@ class CategoriesController extends Controller
}
// Prepare the error message
$error = trans('admin/categories/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('categories.index')->with('error', $error);
return redirect()->route('categories.index')
->with('error', trans('admin/categories/message.does_not_exist'));
}
}

View file

@ -1,9 +1,9 @@
<?php
namespace App\Http\Controllers;
use App\Exceptions\CheckoutNotAllowed;
use App\Models\Asset;
use App\Models\Location;
use App\Models\SnipeModel;
use App\Models\User;
trait CheckInOutRequest

View file

@ -1,14 +1,10 @@
<?php
namespace App\Http\Controllers;
use App\Models\Company;
use Input;
use Lang;
use Redirect;
use View;
use Illuminate\Http\Request;
use Image;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
/**
* This controller handles all actions related to Companies for
@ -21,11 +17,12 @@ final class CompaniesController extends Controller
{
/**
* Returns view to display listing of companies.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @return \Illuminate\Contracts\View\View
* Returns view to display listing of companies.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @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] [<ahimta@gmail.com>]
* @since [v1.8]
* @return \Illuminate\Contracts\View\View
* Returns view to create a new company.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @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,16 +62,7 @@ final class CompaniesController extends Controller
$company = new Company;
$company->name = $request->input('name');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/companies/'.$file_name);
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$company->image = $file_name;
}
$company = $request->handleImages($company);
if ($company->save()) {
return redirect()->route('companies.index')
@ -83,12 +73,13 @@ final class CompaniesController extends Controller
/**
* Return form to edit existing company.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return \Illuminate\Contracts\View\View
* Return form to edit existing company.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($companyId)
{
@ -107,9 +98,10 @@ final class CompaniesController extends Controller
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @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)
{
@ -121,37 +113,7 @@ final class CompaniesController extends Controller
$company->name = $request->input('name');
$old_image = $company->image;
// Set the model's image property to null if the image is being deleted
if ($request->input('image_delete') == 1) {
$company->image = null;
}
if ($request->file('image')) {
$image = $request->file('image');
$file_name = $company->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('companies_upload_path').$file_name);
} else {
$image->move(app('companies_upload_path'), $file_name);
}
$company->image = $file_name;
}
if ((($request->file('image')) && (isset($old_image)) && ($old_image!='')) || ($request->input('image_delete') == 1)) {
try {
unlink(app('companies_upload_path').$old_image);
} catch (\Exception $e) {
\Log::info($e);
}
}
$company = $request->handleImages($company);
if ($company->save()) {
return redirect()->route('companies.index')
@ -162,38 +124,47 @@ final class CompaniesController extends Controller
}
/**
* Delete company
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return \Illuminate\Http\RedirectResponse
* Delete company
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @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);
try {
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'));
} 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'));
}
throw $exception;
}
}
@ -203,9 +174,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);
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace App\Http\Controllers\Components;
use App\Events\CheckoutableCheckedIn;
use App\Events\ComponentCheckedIn;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Component;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
class ComponentCheckinController extends Controller
{
/**
* Returns a view that allows the checkin of a component from an asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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')));
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'));
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace App\Http\Controllers\Components;
use App\Events\CheckoutableCheckedOut;
use App\Events\ComponentCheckedOut;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Component;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Validator;
class ComponentCheckoutController extends Controller
{
/**
* Returns a view that allows the checkout of a component to an asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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(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
]);
event(new CheckoutableCheckedOut($component, $asset, Auth::user(), $request->input('note')));
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
}
}

View file

@ -0,0 +1,199 @@
<?php
namespace App\Http\Controllers\Components;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Company;
use App\Models\Component;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Storage;
/**
* This class controls all actions related to Components for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ComponentsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the components listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
$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);
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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -1,397 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Component;
use App\Models\CustomField;
use App\Models\Setting;
use App\Models\User;
use App\Models\Asset;
use Auth;
use Config;
use DB;
use Input;
use Lang;
use Mail;
use Redirect;
use Slack;
use Str;
use View;
use Validator;
use Illuminate\Http\Request;
use Gate;
use Image;
/**
* This class controls all actions related to Components for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ComponentsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the components listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$component->image = $file_name;
}
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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$component->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$component->image = null;
}
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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
// Prepare the error message
$error = trans('admin/components/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('components.index')->with('error', $error);
}
/**
* Returns a view that allows the checkout of a component to an asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers\Consumables;
use App\Events\CheckoutableCheckedOut;
use App\Http\Controllers\Controller;
use App\Models\Consumable;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
class ConsumableCheckoutController extends Controller
{
/**
* Return a view to checkout a consumable to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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(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'))
]);
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'));
}
}

View file

@ -0,0 +1,196 @@
<?php
namespace App\Http\Controllers\Consumables;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Company;
use App\Models\Consumable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
/**
* This controller handles all actions related to Consumables for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ConsumablesController extends Controller
{
/**
* Return a view to display component information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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(Input::get('purchase_cost'));
$consumable->qty = Helper::ParseFloat(Input::get('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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -1,286 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\Setting;
use App\Models\User;
use Auth;
use Config;
use DB;
use Input;
use Lang;
use Redirect;
use Slack;
use Str;
use View;
use Gate;
use Image;
use App\Http\Requests\ImageUploadRequest;
/**
* This controller handles all actions related to Consumables for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ConsumablesController extends Controller
{
/**
* Return a view to display component information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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();
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;
}
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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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', compact('id')));
}
/**
* Return a view to checkout a consumable to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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'));
}
}

View file

@ -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
{

View file

@ -1,19 +1,12 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CustomFieldRequest;
use View;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use Input;
use Validator;
use Redirect;
use App\Models\AssetModel;
use Lang;
use Auth;
use Illuminate\Http\Request;
use App\Helpers\Helper;
use Log;
use App\Http\Requests\CustomFieldRequest;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use Illuminate\Support\Facades\Auth;
use Redirect;
/**
* This controller handles all actions related to Custom Asset Fields for
@ -29,49 +22,53 @@ class CustomFieldsController extends Controller
{
/**
* Returns a view with a listing of custom fields.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
* Returns a view with a listing of custom fields.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
* Returns a view with a form to create a new custom field.
*
* @see CustomFieldsController::storeField()
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
* Validates and stores a new custom field.
*
* @see CustomFieldsController::createField()
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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] [<snipe@snipe.net>]
* @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] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
* Delete a custom field.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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] [<snipe@snipe.net>]
* @param int $id
* @since [v4.0]
* @return View
*/
* Return a view to edit a custom field
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @param int $id
* @since [v4.0]
* @return Redirect
*/
* Store the updated field
*
* @todo Allow encrypting/decrypting if encryption status changes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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"));

View file

@ -1,17 +1,14 @@
<?php
namespace App\Http\Controllers;
use View;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use Input;
use Validator;
use Redirect;
use App\Models\AssetModel;
use Lang;
use Auth;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use Illuminate\Http\Request;
use Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Validator;
use Redirect;
/**
* This controller handles all actions related to Custom Asset Fields for
@ -26,23 +23,26 @@ use Log;
class CustomFieldsetsController extends Controller
{
/**
* Validates and stores a new custom field.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return View
*/
/**
* Validates and stores a new custom field.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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,26 @@ 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 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'));
}
/**
* Returns a view with a form for creating a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
* Returns a view with a form for creating a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return \Illuminate\Support\Facades\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create()
{
$this->authorize('create', CustomFieldset::class);
@ -77,29 +85,30 @@ class CustomFieldsetsController extends Controller
/**
* Validates and stores a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
* Validates and stores a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @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);
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 +145,14 @@ class CustomFieldsetsController extends Controller
/**
* Validates a custom fieldset and then deletes if it has no models associated.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return View
*/
* Validates a custom fieldset and then deletes if it has no models associated.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy($id)
{
$fieldset = CustomFieldset::find($id);
@ -154,9 +164,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'));

View file

@ -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

View file

@ -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] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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,16 +55,7 @@ class DepartmentsController extends Controller
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/departments/'.$file_name);
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$department->image = $file_name;
}
$department = $request->handleImages($department);
if ($department->save()) {
return redirect()->route("departments.index")->with('success', trans('admin/departments/message.create.success'));
@ -78,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)
{
@ -88,7 +82,7 @@ class DepartmentsController extends Controller
if (isset($department->id)) {
return view('departments/view', compact('department'));
}
return redirect()->route('departments.index')->with('error', trans('admin/departments/message.does_not_exist', compact('id')));
return redirect()->route('departments.index')->with('error', trans('admin/departments/message.does_not_exist'));
}
@ -99,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()
{
@ -115,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)
{
@ -128,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] [<snipe@snipe.net>]
* @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'));
}
@ -164,36 +169,7 @@ class DepartmentsController extends Controller
$department->fill($request->all());
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
$old_image = $department->image;
// Set the model's image property to null if the image is being deleted
if ($request->input('image_delete') == 1) {
$department->image = null;
}
if ($request->file('image')) {
$image = $request->file('image');
$file_name = $department->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('departments_upload_path').$file_name);
} else {
$image->move(app('departments_upload_path'), $file_name);
}
$department->image = $file_name;
}
if ((($request->file('image')) && (isset($old_image)) && ($old_image!='')) || ($request->input('image_delete') == 1)) {
try {
unlink(app('departments_upload_path').$old_image);
} catch (\Exception $e) {
\Log::info($e);
}
}
$department = $request->handleImages($department);
if ($department->save()) {
return redirect()->route("departments.index")->with('success', trans('admin/departments/message.update.success'));

View file

@ -1,16 +1,9 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use Lang;
use App\Models\Depreciation;
use Redirect;
use App\Models\Setting;
use DB;
use Str;
use View;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* This controller handles all actions related to Depreciations for
@ -21,13 +14,14 @@ use Illuminate\Http\Request;
class DepreciationsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the depreciation listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::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 depreciation listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function index()
{
@ -39,12 +33,13 @@ class DepreciationsController extends Controller
/**
* Returns a view that displays a form to create a new depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postCreate()
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
* Returns a view that displays a form to create a new depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postCreate()
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create()
{
@ -63,6 +58,7 @@ class DepreciationsController extends Controller
* @since [v1.0]
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function store(Request $request)
{
@ -84,13 +80,14 @@ class DepreciationsController extends Controller
}
/**
* Returns a view that displays a form to update a depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postEdit()
* @param int $depreciationId
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
* Returns a view that displays a form to update a depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postEdit()
* @param int $depreciationId
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($depreciationId = null)
{
@ -115,6 +112,7 @@ class DepreciationsController extends Controller
* @param int $depreciationId
* @return \Illuminate\Http\RedirectResponse
* @since [v1.0]
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, $depreciationId = null)
{
@ -147,17 +145,18 @@ class DepreciationsController extends Controller
* @since [v1.0]
* @param integer $depreciationId
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy($depreciationId)
{
// Check if the depreciation exists
if (is_null($depreciation = Depreciation::find($depreciationId))) {
if (is_null($depreciation = Depreciation::withCount('models as models_count')->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)
{

View file

@ -1,15 +1,9 @@
<?php
namespace App\Http\Controllers;
use Config;
use Input;
use Lang;
use Redirect;
use App\Models\Setting;
use Validator;
use View;
use App\Models\Group;
use App\Helpers\Helper;
use App\Models\Group;
use Illuminate\Support\Facades\Input;
/**
* This controller handles all actions related to User Groups for
@ -109,7 +103,6 @@ class GroupsController extends Controller
*/
public function update($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')));
}
@ -126,13 +119,14 @@ class GroupsController extends Controller
}
/**
* Validates and deletes the User Group.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getEdit()
* @param int $id
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
* Validates and deletes the User Group.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getEdit()
* @param int $id
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
* @throws \Exception
*/
public function destroy($id = null)
{
@ -152,9 +146,9 @@ class GroupsController extends Controller
* the content for the group detail page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v4.0.11]
* @param $id
* @return \Illuminate\Contracts\View\View
* @since [v4.0.11]
*/
public function show($id)
{

View file

@ -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);
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace App\Http\Controllers\Kits;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Models\PredefinedKit;
use App\Models\PredefinedLicence;
use App\Models\PredefinedModel;
use App\Models\User;
use App\Services\PredefinedKitCheckoutService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
/**
* This controller handles all access kits management:
* list, add/remove/change
*
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
*/
class CheckoutKitController extends Controller
{
public $kitService;
use CheckInOutRequest;
public function __construct(PredefinedKitCheckoutService $kitService)
{
$this->kitService = $kitService;
}
/**
* Show Bulk Checkout Page
*
* @author [D. Minaev.] [<dmitriy.minaev.v@gmail.com>]
* @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.] [<dmitriy.minaev.v@gmail.com>]
* @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
}
}

View file

@ -0,0 +1,469 @@
<?php
namespace App\Http\Controllers\Kits;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Models\PredefinedKit;
use App\Models\PredefinedLicence;
use App\Models\PredefinedModel;
use Illuminate\Http\Request;
/**
* This controller handles all access kits management:
* list, add/remove/change
*
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
*/
class PredefinedKitsController extends Controller
{
/**
* @author [D. Minaev] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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] [<dmitriy.minaev.v@gmail.com>]
* @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
}
}

View file

@ -0,0 +1,105 @@
<?php
namespace App\Http\Controllers\Licenses;
use App\Events\CheckoutableCheckedIn;
use App\Http\Controllers\Controller;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
class LicenseCheckinController extends Controller
{
/**
* Makes the form view to check a license seat back into inventory.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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',
'notes' => 'string',
];
// 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);
}
$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'));
}
}

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