mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Merge branch 'develop' into bulk_edit_custom_fields
This commit is contained in:
commit
f646623a5e
|
@ -2882,6 +2882,76 @@
|
|||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Mezzle",
|
||||
"name": "Martin Meredith",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/570639?v=4",
|
||||
"profile": "https://github.com/Mezzle",
|
||||
"contributions": []
|
||||
},
|
||||
{
|
||||
"login": "dboth",
|
||||
"name": "dboth",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731963?v=4",
|
||||
"profile": "http://dboth.de",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zacharyfleck",
|
||||
"name": "Zachary Fleck",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/87536651?v=4",
|
||||
"profile": "https://github.com/zacharyfleck",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vikaas-cyper",
|
||||
"name": "VIKAAS-A",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/74609912?v=4",
|
||||
"profile": "https://github.com/vikaas-cyper",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ak-piracha",
|
||||
"name": "Abdul Kareem",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/88882041?v=4",
|
||||
"profile": "https://github.com/ak-piracha",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "NojoudAlshehri",
|
||||
"name": "NojoudAlshehri",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/111287779?v=4",
|
||||
"profile": "https://github.com/NojoudAlshehri",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "stefanstidlffg",
|
||||
"name": "Stefan Stidl",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/54367449?v=4",
|
||||
"profile": "https://github.com/stefanstidlffg",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "qay21",
|
||||
"name": "Quentin Aymard",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/87803479?v=4",
|
||||
"profile": "https://github.com/qay21",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
58
.chipperci.yml
Normal file
58
.chipperci.yml
Normal file
|
@ -0,0 +1,58 @@
|
|||
version: 1
|
||||
|
||||
environment:
|
||||
php: 8.0
|
||||
node: 12
|
||||
|
||||
services:
|
||||
- mysql: 5.7
|
||||
- dusk:
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
pipeline:
|
||||
- name: Setup
|
||||
cmd: |
|
||||
cp -v .env.example .env
|
||||
|
||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Generate Key
|
||||
cmd: |
|
||||
php artisan key:generate --force
|
||||
|
||||
- name: Passport Keys
|
||||
cmd: |
|
||||
php artisan passport:keys
|
||||
|
||||
- name: Run Migrations
|
||||
cmd: |
|
||||
# php artisan migrate --force
|
||||
|
||||
- name: PHPUnit Unit Tests
|
||||
cmd: |
|
||||
# php artisan test --testsuite Unit
|
||||
|
||||
- name: PHPUnit Feature Tests
|
||||
cmd: |
|
||||
# php artisan test --testsuite Feature
|
||||
|
||||
# - name: Browser Tests
|
||||
# cmd: |
|
||||
# cp -v .env.dusk.example .env.dusk.ci
|
||||
# sed -i "s@APP_ENV=.*@APP_ENV=ci@g" .env.dusk.ci
|
||||
# sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci
|
||||
# #sed -i "s@DB_HOST=.*@DB_HOST=mysql@g" .env.dusk.ci
|
||||
# sed -i "s@DB_HOST=.*@DB_HOST=$DB_HOST@g" .env.dusk.ci
|
||||
# sed -i "s@DB_USERNAME=.*@DB_USERNAME=chipperci@g" .env.dusk.ci
|
||||
# sed -i "s@DB_DATABASE=.*@DB_DATABASE=chipperci@g" .env.dusk.ci
|
||||
# sed -i "s@DB_PASSWORD=.*@DB_PASSWORD=secret@g" .env.dusk.ci
|
||||
#
|
||||
# php -S [::0]:8000 -t public 2>server.log &
|
||||
# sleep 2
|
||||
# php artisan dusk:chrome-driver $CHROME_DRIVER
|
||||
# php artisan dusk --env=ci
|
|
@ -175,6 +175,15 @@ REQUIRE_SAML=false
|
|||
API_THROTTLE_PER_MINUTE=120
|
||||
CSV_ESCAPE_FORMULAS=true
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: HASHING
|
||||
# --------------------------------------------
|
||||
HASHING_DRIVER='bcrypt'
|
||||
BCRYPT_ROUNDS=10
|
||||
ARGON_MEMORY=1024
|
||||
ARGON_THREADS=2
|
||||
ARGON_TIME=2
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SCIM
|
||||
# --------------------------------------------
|
||||
|
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
@ -2,8 +2,6 @@ name: Feature Request
|
|||
description: Suggest an idea for this project
|
||||
title: "[Feature Request]: "
|
||||
labels: ["feature request"]
|
||||
assignees:
|
||||
- snipe
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
|
16
.github/autolabeler.yml
vendored
16
.github/autolabeler.yml
vendored
|
@ -1,18 +1,22 @@
|
|||
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*", "*livewire*"]
|
||||
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*", "resources/views/livewire/*"]
|
||||
skins: ["*.js", "*.css", "*.scss", "*.less"]
|
||||
css: ["*.css","*.scss", "*.less"]
|
||||
backend: ["/app/*", "*.php"]
|
||||
javascript: ["*.js", "package.json", "package.lock"]
|
||||
backend: ["/app/*", "composer.json", "composer.lock"]
|
||||
translations: ["/resources/lang"]
|
||||
livewire: ["/app/Http/Livewire/*", "resources/views/livewire/*"]
|
||||
backups: ["*backup*"]
|
||||
restore: ["*restore*"]
|
||||
saml: ["*saml*"]
|
||||
scim: ["*scim*"]
|
||||
custom fields: ["*fields*", "*fieldsets*"]
|
||||
dependencies: ["composer.json"]
|
||||
dependencies: ["composer.json", "composer.lock", "package.json", "package.lock"]
|
||||
consumables: ["*consumables*"]
|
||||
api: ["/app/Http/Controllers/api/*"]
|
||||
api: ["/app/Http/Controllers/Api/*"]
|
||||
notifications: ["/app/Notifications/*"]
|
||||
importer: ["/app/Importer/*"]
|
||||
importer: ["/app/Importer/*","/app/Http/Livewire/Importer.php", "resources/views/livewire/importer.php"]
|
||||
cli / artisan: ["/app/Console/*"]
|
||||
LDAP: ["*LDAP*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
|
||||
LDAP: ["*Ldap*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
|
||||
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
|
||||
tests: ["/tests/*", "/stubs"]
|
||||
config: .github
|
||||
|
|
2
.github/workflows/docker-alpine.yml
vendored
2
.github/workflows/docker-alpine.yml
vendored
|
@ -76,7 +76,7 @@ jobs:
|
|||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.alpine
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
|
||||
# but we ONLY do an image push to DockerHub if it's NOT a PR
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -76,7 +76,7 @@ jobs:
|
|||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
|
||||
# but we ONLY do an image push to DockerHub if it's NOT a PR
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
|
33
Dockerfile
33
Dockerfile
|
@ -1,4 +1,4 @@
|
|||
FROM ubuntu:20.04
|
||||
FROM ubuntu:22.04
|
||||
LABEL maintainer="Brady Wetherington <bwetherington@grokability.com>"
|
||||
|
||||
# No need to add `apt-get clean` here, reference:
|
||||
|
@ -14,16 +14,16 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
|
|||
apt-utils \
|
||||
apache2 \
|
||||
apache2-bin \
|
||||
libapache2-mod-php7.4 \
|
||||
php7.4-curl \
|
||||
php7.4-ldap \
|
||||
php7.4-mysql \
|
||||
php7.4-gd \
|
||||
php7.4-xml \
|
||||
php7.4-mbstring \
|
||||
php7.4-zip \
|
||||
php7.4-bcmath \
|
||||
php7.4-redis \
|
||||
libapache2-mod-php8.1 \
|
||||
php8.1-curl \
|
||||
php8.1-ldap \
|
||||
php8.1-mysql \
|
||||
php8.1-gd \
|
||||
php8.1-xml \
|
||||
php8.1-mbstring \
|
||||
php8.1-zip \
|
||||
php8.1-bcmath \
|
||||
php8.1-redis \
|
||||
php-memcached \
|
||||
patch \
|
||||
curl \
|
||||
|
@ -38,9 +38,10 @@ gcc \
|
|||
make \
|
||||
autoconf \
|
||||
libc-dev \
|
||||
libldap-common \
|
||||
pkg-config \
|
||||
libmcrypt-dev \
|
||||
php7.4-dev \
|
||||
php8.1-dev \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
dnsutils \
|
||||
|
@ -50,16 +51,16 @@ dnsutils \
|
|||
RUN curl -L -O https://github.com/pear/pearweb_phars/raw/master/go-pear.phar
|
||||
RUN php go-pear.phar
|
||||
|
||||
RUN pecl install mcrypt-1.0.3
|
||||
RUN pecl install mcrypt
|
||||
|
||||
RUN bash -c "echo extension=/usr/lib/php/20190902/mcrypt.so > /etc/php/7.4/mods-available/mcrypt.ini"
|
||||
RUN bash -c "echo extension=/usr/lib/php/20210902/mcrypt.so > /etc/php/8.1/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.4/apache2/php.ini
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.4/cli/php.ini
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.1/apache2/php.ini
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/8.1/cli/php.ini
|
||||
|
||||
RUN useradd -m --uid 1000 --gid 50 docker
|
||||
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
FROM alpine:3.14.2
|
||||
FROM alpine:3.17.3
|
||||
# Apache + PHP
|
||||
RUN apk add --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 \
|
||||
php7-dom \
|
||||
php7-xmlwriter \
|
||||
php7-xmlreader \
|
||||
php7-sodium \
|
||||
php7-redis \
|
||||
php7-pecl-memcached \
|
||||
php81 \
|
||||
php81-common \
|
||||
php81-apache2 \
|
||||
php81-curl \
|
||||
php81-ldap \
|
||||
php81-mysqli \
|
||||
php81-gd \
|
||||
php81-xml \
|
||||
php81-mbstring \
|
||||
php81-zip \
|
||||
php81-ctype \
|
||||
php81-tokenizer \
|
||||
php81-pdo_mysql \
|
||||
php81-openssl \
|
||||
php81-bcmath \
|
||||
php81-phar \
|
||||
php81-json \
|
||||
php81-iconv \
|
||||
php81-fileinfo \
|
||||
php81-simplexml \
|
||||
php81-session \
|
||||
php81-dom \
|
||||
php81-xmlwriter \
|
||||
php81-xmlreader \
|
||||
php81-sodium \
|
||||
php81-redis \
|
||||
php81-pecl-memcached \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
|
@ -41,7 +41,7 @@ COPY docker/column-statistics.cnf /etc/mysql/conf.d/column-statistics.cnf
|
|||
# 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
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php81/php.ini
|
||||
COPY docker/000-default-2.4.conf /etc/apache2/conf.d/default.conf
|
||||
|
||||
# Enable mod_rewrite
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
ARG ENVIRONMENT=production
|
||||
ARG SNIPEIT_RELEASE=5.1.3
|
||||
ARG PHP_VERSION=7.4.16
|
||||
ARG PHP_ALPINE_VERSION=3.13
|
||||
ARG COMPOSER_VERSION=2.0.11
|
||||
ARG SNIPEIT_RELEASE=6.1.0
|
||||
ARG PHP_VERSION=8.2
|
||||
ARG PHP_ALPINE_VERSION=3.17
|
||||
ARG COMPOSER_VERSION=2
|
||||
|
||||
# Cannot use arguments with 'COPY --from' workaround
|
||||
# https://github.com/moby/moby/issues/34482#issuecomment-454716952
|
||||
|
@ -52,7 +52,7 @@ RUN { \
|
|||
|
||||
# Install php extensions inside docker containers easily
|
||||
# https://github.com/mlocati/docker-php-extension-installer
|
||||
COPY --from=mlocati/php-extension-installer:1.2.19 /usr/bin/install-php-extensions /usr/local/bin/
|
||||
COPY --from=mlocati/php-extension-installer:2.1.15 /usr/bin/install-php-extensions /usr/local/bin/
|
||||
RUN set -eux; \
|
||||
install-php-extensions \
|
||||
bcmath \
|
||||
|
|
10
README.md
10
README.md
|
@ -1,5 +1,5 @@
|
|||
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-317-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-325-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
||||
|
@ -66,8 +66,11 @@ Since the release of the JSON REST API, several third-party developers have been
|
|||
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
|
||||
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
|
||||
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
|
||||
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@RodneyLeeBrands](https://github.com/RodneyLeeBrands) - Python script to synchronize information between Mosyle and Snipe-IT
|
||||
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT
|
||||
- [WWW::SnipeIT](https://github.com/SEDC/perl-www-snipeit) by [@SEDC](https://github.com/SEDC) - perl module for accessing the API
|
||||
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
|
||||
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
|
||||
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
|
||||
|
||||
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
|
||||
|
||||
|
@ -141,7 +144,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
|||
| [<img src="https://avatars.githubusercontent.com/u/32363424?v=4" width="110px;"/><br /><sub>Peace</sub>](https://github.com/julian-piehl)<br />[💻](https://github.com/snipe/snipe-it/commits?author=julian-piehl "Code") | [<img src="https://avatars.githubusercontent.com/u/231528?v=4" width="110px;"/><br /><sub>Kyle Gordon</sub>](https://github.com/kylegordon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kylegordon "Code") | [<img src="https://avatars.githubusercontent.com/u/53009155?v=4" width="110px;"/><br /><sub>Katharina Drexel</sub>](http://www.bfh.ch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sunflowerbofh "Code") | [<img src="https://avatars.githubusercontent.com/u/1931963?v=4" width="110px;"/><br /><sub>David Sferruzza</sub>](https://david.sferruzza.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dsferruzza "Code") | [<img src="https://avatars.githubusercontent.com/u/19511639?v=4" width="110px;"/><br /><sub>Rick Nelson</sub>](https://github.com/rnelsonee)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rnelsonee "Code") | [<img src="https://avatars.githubusercontent.com/u/94169344?v=4" width="110px;"/><br /><sub>BasO12</sub>](https://github.com/BasO12)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BasO12 "Code") | [<img src="https://avatars.githubusercontent.com/u/111710123?v=4" width="110px;"/><br /><sub>Vautia</sub>](https://github.com/Vautia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Vautia "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") | [<img src="https://avatars.githubusercontent.com/u/658865?v=4" width="110px;"/><br /><sub>Andrew Savinykh</sub>](https://github.com/AndrewSav)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AndrewSav "Code") | [<img src="https://avatars.githubusercontent.com/u/1155067?v=4" width="110px;"/><br /><sub>Tadayuki Onishi</sub>](https://kenchan0130.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kenchan0130 "Code") | [<img src="https://avatars.githubusercontent.com/u/112496896?v=4" width="110px;"/><br /><sub>Florian</sub>](https://github.com/floschoepfer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=floschoepfer "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/7305753?v=4" width="110px;"/><br /><sub>Spencer Long</sub>](http://spencerlong.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=spencerrlongg "Code") | [<img src="https://avatars.githubusercontent.com/u/1141514?v=4" width="110px;"/><br /><sub>Marcus Moore</sub>](https://github.com/marcusmoore)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcusmoore "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/7305753?v=4" width="110px;"/><br /><sub>Spencer Long</sub>](http://spencerlong.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=spencerrlongg "Code") | [<img src="https://avatars.githubusercontent.com/u/1141514?v=4" width="110px;"/><br /><sub>Marcus Moore</sub>](https://github.com/marcusmoore)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcusmoore "Code") | [<img src="https://avatars.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://github.com/Mezzle)<br /> | [<img src="https://avatars.githubusercontent.com/u/5731963?v=4" width="110px;"/><br /><sub>dboth</sub>](http://dboth.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dboth "Code") | [<img src="https://avatars.githubusercontent.com/u/87536651?v=4" width="110px;"/><br /><sub>Zachary Fleck</sub>](https://github.com/zacharyfleck)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zacharyfleck "Code") | [<img src="https://avatars.githubusercontent.com/u/74609912?v=4" width="110px;"/><br /><sub>VIKAAS-A</sub>](https://github.com/vikaas-cyper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vikaas-cyper "Code") | [<img src="https://avatars.githubusercontent.com/u/88882041?v=4" width="110px;"/><br /><sub>Abdul Kareem</sub>](https://github.com/ak-piracha)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ak-piracha "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
|
|
@ -56,7 +56,7 @@ class CheckoutLicenseToAllUsers extends Command
|
|||
return false;
|
||||
}
|
||||
|
||||
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '==', 1)->with('licenses')->get();
|
||||
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '=', 1)->with('licenses')->get();
|
||||
|
||||
if ($users->count() > $license->getAvailSeatsCountAttribute()) {
|
||||
$this->info('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
|
||||
|
|
|
@ -20,13 +20,14 @@ class CreateAdmin extends Command
|
|||
* @property string $password
|
||||
* @property boolean $activated
|
||||
* @property boolean $show_in_list
|
||||
* @property boolean $autoassign_licenses
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property mixed $created_by
|
||||
*/
|
||||
|
||||
|
||||
|
||||
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?}';
|
||||
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?} {autoassign_licenses?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -54,6 +55,9 @@ class CreateAdmin extends Command
|
|||
$email = $this->option('email');
|
||||
$password = $this->option('password');
|
||||
$show_in_list = $this->argument('show_in_list');
|
||||
$autoassign_licenses = $this->argument('autoassign_licenses');
|
||||
|
||||
|
||||
|
||||
if (($first_name == '') || ($last_name == '') || ($username == '') || ($email == '') || ($password == '')) {
|
||||
$this->info('ERROR: All fields are required.');
|
||||
|
@ -70,6 +74,11 @@ class CreateAdmin extends Command
|
|||
if ($show_in_list == 'false') {
|
||||
$user->show_in_list = 0;
|
||||
}
|
||||
|
||||
if ($autoassign_licenses == 'false') {
|
||||
$user->autoassign_licenses = 0;
|
||||
}
|
||||
|
||||
if ($user->save()) {
|
||||
$this->info('New user created');
|
||||
$user->groups()->attach(1);
|
||||
|
|
|
@ -62,6 +62,7 @@ class LdapSync extends Command
|
|||
$ldap_result_phone = Setting::getSettings()->ldap_phone_field;
|
||||
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
|
||||
$ldap_result_country = Setting::getSettings()->ldap_country;
|
||||
$ldap_result_location = Setting::getSettings()->ldap_location;
|
||||
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
||||
$ldap_result_manager = Setting::getSettings()->ldap_manager;
|
||||
$ldap_default_group = Setting::getSettings()->ldap_default_group;
|
||||
|
@ -209,8 +210,11 @@ class LdapSync extends Command
|
|||
$item['country'] = $results[$i][$ldap_result_country][0] ?? '';
|
||||
$item['department'] = $results[$i][$ldap_result_dept][0] ?? '';
|
||||
$item['manager'] = $results[$i][$ldap_result_manager][0] ?? '';
|
||||
$item['location'] = $results[$i][$ldap_result_location][0] ?? '';
|
||||
|
||||
|
||||
$location = Location::firstOrCreate([
|
||||
'name' => $item['location'],
|
||||
]);
|
||||
$department = Department::firstOrCreate([
|
||||
'name' => $item['department'],
|
||||
]);
|
||||
|
@ -236,6 +240,7 @@ class LdapSync extends Command
|
|||
$user->jobtitle = $item['jobtitle'];
|
||||
$user->country = $item['country'];
|
||||
$user->department_id = $department->id;
|
||||
$user->location_id = $location->id;
|
||||
|
||||
if($item['manager'] != null) {
|
||||
// Check Cache first
|
||||
|
|
|
@ -11,7 +11,7 @@ class SystemBackup extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'snipeit:backup';
|
||||
protected $signature = 'snipeit:backup {--filename=}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -37,7 +37,18 @@ class SystemBackup extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
//
|
||||
$this->call('backup:run');
|
||||
if ($this->option('filename')) {
|
||||
$filename = $this->option('filename');
|
||||
|
||||
// Make sure the filename ends in .zip
|
||||
if (!ends_with($filename, '.zip')) {
|
||||
$filename = $filename.'.zip';
|
||||
}
|
||||
|
||||
$this->call('backup:run', ['--filename' => $filename]);
|
||||
} else {
|
||||
$this->call('backup:run');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
|
|||
use Log;
|
||||
use Throwable;
|
||||
use JsonException;
|
||||
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ class Handler extends ExceptionHandler
|
|||
\League\OAuth2\Server\Exception\OAuthServerException::class,
|
||||
JsonException::class,
|
||||
SCIMException::class, //these generally don't need to be reported
|
||||
InvalidFormatException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -69,21 +70,34 @@ class Handler extends ExceptionHandler
|
|||
// Invalid JSON exception
|
||||
// TODO: don't understand why we have to do this when we have the invalidJson() method, below, but, well, whatever
|
||||
if ($e instanceof JsonException) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Invalid JSON'), 422);
|
||||
}
|
||||
|
||||
// Handle SCIM exceptions
|
||||
if ($e instanceof SCIMException) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid SCIM Request'), 400);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Invalid SCIM Request'), 400);
|
||||
}
|
||||
|
||||
// Handle Ajax requests that fail because the model doesn't exist
|
||||
// Handle standard requests that fail because Carbon cannot parse the date on validation (when a submitted date value is definitely not a date)
|
||||
if ($e instanceof InvalidFormatException) {
|
||||
return redirect()->back()->withInput()->with('error', trans('validation.date', ['attribute' => 'date']));
|
||||
}
|
||||
|
||||
// Handle API requests that fail
|
||||
if ($request->ajax() || $request->wantsJson()) {
|
||||
|
||||
// Handle API requests that fail because Carbon cannot parse the date on validation (when a submitted date value is definitely not a date)
|
||||
if ($e instanceof InvalidFormatException) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('validation.date', ['attribute' => 'date'])), 200);
|
||||
}
|
||||
|
||||
// Handle API requests that fail because the model doesn't exist
|
||||
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
|
||||
$className = last(explode('\\', $e->getModel()));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $className . ' not found'), 200);
|
||||
}
|
||||
|
||||
// Handle API requests that fail because of an HTTP status code and return a useful error message
|
||||
if ($this->isHttpException($e)) {
|
||||
|
||||
$statusCode = $e->getStatusCode();
|
||||
|
@ -103,6 +117,8 @@ class Handler extends ExceptionHandler
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($this->isHttpException($e) && (isset($statusCode)) && ($statusCode == '404' )) {
|
||||
return response()->view('layouts/basic', [
|
||||
'content' => view('errors/404')
|
||||
|
|
|
@ -77,7 +77,7 @@ class AccessoriesController extends Controller
|
|||
$accessory->manufacturer_id = request('manufacturer_id');
|
||||
$accessory->model_number = request('model_number');
|
||||
$accessory->purchase_date = request('purchase_date');
|
||||
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
|
||||
$accessory->purchase_cost = request('purchase_cost');
|
||||
$accessory->qty = request('qty');
|
||||
$accessory->user_id = Auth::user()->id;
|
||||
$accessory->supplier_id = request('supplier_id');
|
||||
|
@ -180,7 +180,7 @@ class AccessoriesController extends Controller
|
|||
$accessory->order_number = request('order_number');
|
||||
$accessory->model_number = request('model_number');
|
||||
$accessory->purchase_date = request('purchase_date');
|
||||
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
|
||||
$accessory->purchase_cost = request('purchase_cost');
|
||||
$accessory->qty = request('qty');
|
||||
$accessory->supplier_id = request('supplier_id');
|
||||
$accessory->notes = request('notes');
|
||||
|
|
|
@ -25,11 +25,16 @@ class AccessoryCheckoutController extends Controller
|
|||
public function create($accessoryId)
|
||||
{
|
||||
// Check if the accessory exists
|
||||
if (is_null($accessory = Accessory::find($accessoryId))) {
|
||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
||||
// Redirect to the accessory management page with error
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
||||
}
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($accessory->numRemaining() <= 0){
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
if ($accessory->category) {
|
||||
$this->authorize('checkout', $accessory);
|
||||
|
||||
|
@ -55,17 +60,23 @@ class AccessoryCheckoutController extends Controller
|
|||
public function store(Request $request, $accessoryId)
|
||||
{
|
||||
// Check if the accessory exists
|
||||
if (is_null($accessory = Accessory::find($accessoryId))) {
|
||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
||||
// Redirect to the accessory management page with error
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.user_not_found'));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $accessory);
|
||||
|
||||
if (! $user = User::find($request->input('assigned_to'))) {
|
||||
if (!$user = User::find($request->input('assigned_to'))) {
|
||||
return redirect()->route('accessories.checkout.show', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
|
||||
}
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($accessory->numRemaining() <= 0){
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
|
||||
// Update the accessory data
|
||||
$accessory->assigned_to = e($request->input('assigned_to'));
|
||||
|
||||
|
|
|
@ -121,7 +121,6 @@ class AcceptanceController extends Controller
|
|||
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
||||
$sig_filename='';
|
||||
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
|
||||
/**
|
||||
|
@ -153,12 +152,14 @@ class AcceptanceController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// this is horrible
|
||||
switch($acceptance->checkoutable_type){
|
||||
case 'App\Models\Asset':
|
||||
$pdf_view_route ='account.accept.accept-asset-eula';
|
||||
$asset_model = AssetModel::find($item->model_id);
|
||||
if (!$asset_model) {
|
||||
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
||||
}
|
||||
$display_model = $asset_model->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
@ -167,7 +168,7 @@ class AcceptanceController extends Controller
|
|||
$pdf_view_route ='account.accept.accept-accessory-eula';
|
||||
$accessory = Accessory::find($item->id);
|
||||
$display_model = $accessory->name;
|
||||
$assigned_to = User::find($item->assignedTo);
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\LicenseSeat':
|
||||
|
@ -250,11 +251,15 @@ class AcceptanceController extends Controller
|
|||
// This is the most horriblest
|
||||
switch($acceptance->checkoutable_type){
|
||||
case 'App\Models\Asset':
|
||||
$asset_model = AssetModel::find($item->model_id);
|
||||
$display_model = $asset_model->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\Accessory':
|
||||
$assigned_to = User::find($item->assignedTo);
|
||||
$accessory = Accessory::find($item->id);
|
||||
$display_model = $accessory->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
|
||||
case 'App\Models\LicenseSeat':
|
||||
|
@ -266,6 +271,8 @@ class AcceptanceController extends Controller
|
|||
break;
|
||||
|
||||
case 'App\Models\Consumable':
|
||||
$consumable = Consumable::find($item->id);
|
||||
$display_model = $consumable->name;
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
break;
|
||||
}
|
||||
|
@ -289,4 +296,4 @@ class AcceptanceController extends Controller
|
|||
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,12 +80,9 @@ class AccessoriesController extends Controller
|
|||
$accessories->where('notes','=',$request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($accessories) && ($request->get('offset') > $accessories->count())) ? $accessories->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $accessories->count()) ? $accessories->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort_override = $request->input('sort');
|
||||
|
@ -153,7 +150,7 @@ class AccessoriesController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', Accessory::class);
|
||||
$accessory = Accessory::findOrFail($id);
|
||||
$accessory = Accessory::withCount('users as users_count')->findOrFail($id);
|
||||
|
||||
return (new AccessoriesTransformer)->transformAccessory($accessory);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class AssetMaintenancesController extends Controller
|
|||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
|
||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
|
||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'admin');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$maintenances = $maintenances->TextSearch($request->input('search'));
|
||||
|
@ -55,12 +55,9 @@ class AssetMaintenancesController extends Controller
|
|||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($maintenances) && ($request->get('offset') > $maintenances->count())) ? $maintenances->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $maintenances->count()) ? $maintenances->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$allowed_columns = [
|
||||
'id',
|
||||
|
@ -74,7 +71,8 @@ class AssetMaintenancesController extends Controller
|
|||
'asset_tag',
|
||||
'asset_name',
|
||||
'user_id',
|
||||
'supplier'
|
||||
'supplier',
|
||||
'is_warranty',
|
||||
];
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
|
@ -121,7 +119,7 @@ class AssetMaintenancesController extends Controller
|
|||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
|
||||
$assetMaintenance->cost = $request->input('cost');
|
||||
$assetMaintenance->notes = e($request->input('notes'));
|
||||
$asset = Asset::find(e($request->input('asset_id')));
|
||||
|
||||
|
@ -178,7 +176,7 @@ class AssetMaintenancesController extends Controller
|
|||
|
||||
$assetMaintenance->supplier_id = e($request->input('supplier_id'));
|
||||
$assetMaintenance->is_warranty = e($request->input('is_warranty'));
|
||||
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
|
||||
$assetMaintenance->cost = $request->input('cost');
|
||||
$assetMaintenance->notes = e($request->input('notes'));
|
||||
|
||||
$asset = Asset::find(request('asset_id'));
|
||||
|
|
|
@ -63,7 +63,7 @@ class AssetModelsController extends Controller
|
|||
'models.deleted_at',
|
||||
'models.updated_at',
|
||||
])
|
||||
->with('category', 'depreciation', 'manufacturer', 'fieldset')
|
||||
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues')
|
||||
->withCount('assets as assets_count');
|
||||
|
||||
if ($request->input('status')=='deleted') {
|
||||
|
@ -78,12 +78,9 @@ class AssetModelsController extends Controller
|
|||
$assetmodels->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($assetmodels) && ($request->get('offset') > $assetmodels->count())) ? $assetmodels->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $assetmodels->count()) ? $assetmodels->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'models.created_at';
|
||||
|
|
|
@ -136,76 +136,10 @@ class AssetsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
if ($request->filled('status_id')) {
|
||||
$assets->where('assets.status_id', '=', $request->input('status_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_tag')) {
|
||||
$assets->where('assets.asset_tag', '=', $request->input('asset_tag'));
|
||||
}
|
||||
|
||||
if ($request->filled('serial')) {
|
||||
$assets->where('assets.serial', '=', $request->input('serial'));
|
||||
}
|
||||
|
||||
if ($request->input('requestable') == 'true') {
|
||||
$assets->where('assets.requestable', '=', '1');
|
||||
}
|
||||
|
||||
if ($request->filled('model_id')) {
|
||||
$assets->InModelList([$request->input('model_id')]);
|
||||
}
|
||||
|
||||
if ($request->filled('category_id')) {
|
||||
$assets->InCategory($request->input('category_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$assets->where('assets.location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('rtd_location_id')) {
|
||||
$assets->where('assets.rtd_location_id', '=', $request->input('rtd_location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_eol_date')) {
|
||||
$assets->where('assets.asset_eol_date', '=', $request->input('asset_eol_date'));
|
||||
}
|
||||
|
||||
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
|
||||
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
|
||||
->where('assets.assigned_type', '=', $request->input('assigned_type'));
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$assets->where('assets.company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('manufacturer_id')) {
|
||||
$assets->ByManufacturer($request->input('manufacturer_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('depreciation_id')) {
|
||||
$assets->ByDepreciationId($request->input('depreciation_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('byod')) {
|
||||
$assets->where('assets.byod', '=', $request->input('byod'));
|
||||
}
|
||||
|
||||
$request->filled('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($assets) && ($request->get('offset') > $assets->count())) ? $assets->count() : $request->get('offset', 0);
|
||||
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
|
@ -304,6 +238,71 @@ class AssetsController extends Controller
|
|||
$assets->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
// Leave these under the TextSearch scope, else the fuzziness will override the specific ID (status ID, etc) requested
|
||||
if ($request->filled('status_id')) {
|
||||
$assets->where('assets.status_id', '=', $request->input('status_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_tag')) {
|
||||
$assets->where('assets.asset_tag', '=', $request->input('asset_tag'));
|
||||
}
|
||||
|
||||
if ($request->filled('serial')) {
|
||||
$assets->where('assets.serial', '=', $request->input('serial'));
|
||||
}
|
||||
|
||||
if ($request->input('requestable') == 'true') {
|
||||
$assets->where('assets.requestable', '=', '1');
|
||||
}
|
||||
|
||||
if ($request->filled('model_id')) {
|
||||
$assets->InModelList([$request->input('model_id')]);
|
||||
}
|
||||
|
||||
if ($request->filled('category_id')) {
|
||||
$assets->InCategory($request->input('category_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$assets->where('assets.location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('rtd_location_id')) {
|
||||
$assets->where('assets.rtd_location_id', '=', $request->input('rtd_location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_eol_date')) {
|
||||
$assets->where('assets.asset_eol_date', '=', $request->input('asset_eol_date'));
|
||||
}
|
||||
|
||||
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
|
||||
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
|
||||
->where('assets.assigned_type', '=', $request->input('assigned_type'));
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$assets->where('assets.company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('manufacturer_id')) {
|
||||
$assets->ByManufacturer($request->input('manufacturer_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('depreciation_id')) {
|
||||
$assets->ByDepreciationId($request->input('depreciation_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('byod')) {
|
||||
$assets->where('assets.byod', '=', $request->input('byod'));
|
||||
}
|
||||
|
||||
if ($request->filled('order_number')) {
|
||||
$assets->where('assets.order_number', '=', $request->get('order_number'));
|
||||
}
|
||||
|
||||
// This is kinda gross, but we need to do this because the Bootstrap Tables
|
||||
// API passes custom field ordering as custom_fields.fieldname, and we have to strip
|
||||
|
@ -463,7 +462,7 @@ class AssetsController extends Controller
|
|||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$this->authorize('view', License::class);
|
||||
$asset = Asset::where('id', $id)->withTrashed()->first();
|
||||
$asset = Asset::where('id', $id)->withTrashed()->firstorfail();
|
||||
$licenses = $asset->licenses()->get();
|
||||
|
||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||
|
@ -554,7 +553,8 @@ class AssetsController extends Controller
|
|||
$asset->depreciate = '0';
|
||||
$asset->status_id = $request->get('status_id', 0);
|
||||
$asset->warranty_months = $request->get('warranty_months', null);
|
||||
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost')); // this is the API's store method, so I don't know that I want to do this? Confusing. FIXME (or not?!)
|
||||
$asset->purchase_cost = $request->get('purchase_cost');
|
||||
$asset->asset_eol_date = $request->get('asset_eol_date', $asset->present()->eol_date());
|
||||
$asset->purchase_date = $request->get('purchase_date', null);
|
||||
$asset->assigned_to = $request->get('assigned_to', null);
|
||||
$asset->supplier_id = $request->get('supplier_id');
|
||||
|
@ -562,6 +562,7 @@ class AssetsController extends Controller
|
|||
$asset->rtd_location_id = $request->get('rtd_location_id', null);
|
||||
$asset->location_id = $request->get('rtd_location_id', null);
|
||||
|
||||
|
||||
/**
|
||||
* this is here just legacy reasons. Api\AssetController
|
||||
* used image_source once to allow encoded image uploads.
|
||||
|
@ -575,6 +576,7 @@ class AssetsController extends Controller
|
|||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
|
@ -832,7 +834,6 @@ class AssetsController extends Controller
|
|||
|
||||
} elseif (request('checkout_to_type') == 'asset') {
|
||||
$target = Asset::where('id', '!=', $asset_id)->find(request('assigned_asset'));
|
||||
$asset->location_id = $target->rtd_location_id;
|
||||
// Override with the asset's location_id if it has one
|
||||
$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
|
||||
$error_payload['target_id'] = $request->input('assigned_asset');
|
||||
|
|
|
@ -67,8 +67,6 @@ class CategoriesController extends Controller
|
|||
$categories = $categories->withCount('showableAssets as assets_count');
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$categories = $categories->TextSearch($request->input('search'));
|
||||
}
|
||||
|
@ -93,14 +91,9 @@ class CategoriesController extends Controller
|
|||
$categories->where('checkin_email', '=', $request->input('checkin_email'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($categories) && ($request->get('offset') > $categories->count())) ? $categories->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $categories->count()) ? $categories->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets_count';
|
||||
|
|
|
@ -48,12 +48,10 @@ class CompaniesController extends Controller
|
|||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($companies) && ($request->get('offset') > $companies->count())) ? $companies->count() : $request->get('offset', 0);
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $companies->count()) ? $companies->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Http\Requests\ImageUploadRequest;
|
|||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Events\ComponentCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class ComponentsController extends Controller
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ class ComponentsController extends Controller
|
|||
|
||||
|
||||
$components = Company::scopeCompanyables(Component::select('components.*')
|
||||
->with('company', 'location', 'category', 'assets'));
|
||||
->with('company', 'location', 'category', 'assets', 'supplier'));
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$components = $components->TextSearch($request->input('search'));
|
||||
|
@ -63,6 +64,10 @@ class ComponentsController extends Controller
|
|||
$components->where('category_id', '=', $request->input('category_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$components->where('supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$components->where('location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
@ -71,14 +76,10 @@ class ComponentsController extends Controller
|
|||
$components->where('notes','=',$request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($components) && ($request->get('offset') > $components->count())) ? $components->count() : $request->get('offset', 0);
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $components->count()) ? $components->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort_override = $request->input('sort');
|
||||
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at';
|
||||
|
@ -93,6 +94,9 @@ class ComponentsController extends Controller
|
|||
case 'company':
|
||||
$components = $components->OrderCompany($order);
|
||||
break;
|
||||
case 'supplier':
|
||||
$components = $components->OrderSupplier($order);
|
||||
break;
|
||||
default:
|
||||
$components = $components->orderBy($column_sort, $order);
|
||||
break;
|
||||
|
@ -225,20 +229,30 @@ class ComponentsController extends Controller
|
|||
public function checkout(Request $request, $componentId)
|
||||
{
|
||||
// Check if the component exists
|
||||
if (is_null($component = Component::find($componentId))) {
|
||||
if (!$component = Component::find($componentId)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.does_not_exist')));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $component);
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'asset_id' => 'required|exists:assets,id',
|
||||
'assigned_qty' => "required|numeric|min:1|digits_between:1,".$component->numRemaining(),
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', $validator->errors()));
|
||||
|
||||
}
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($component->numRemaining() <= $request->get('assigned_qty')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->get('assigned_qty')])));
|
||||
}
|
||||
|
||||
if ($component->numRemaining() >= $request->get('assigned_qty')) {
|
||||
|
||||
if (!$asset = Asset::find($request->input('assigned_to'))) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')));
|
||||
}
|
||||
|
||||
// Update the accessory data
|
||||
$asset = Asset::find($request->input('assigned_to'));
|
||||
$component->assigned_to = $request->input('assigned_to');
|
||||
|
||||
$component->assets()->attach($component->id, [
|
||||
|
@ -255,7 +269,7 @@ class ComponentsController extends Controller
|
|||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Not enough components remaining: '.$component->numRemaining().' remaining, '.$request->get('assigned_qty').' requested.'));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->get('assigned_qty')])));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,6 +75,10 @@ class ConsumablesController extends Controller
|
|||
$consumables->where('manufacturer_id', '=', $request->input('manufacturer_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$consumables->where('supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$consumables->where('location_id','=',$request->input('location_id'));
|
||||
}
|
||||
|
@ -84,12 +88,9 @@ class ConsumablesController extends Controller
|
|||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($consumables) && ($request->get('offset') > $consumables->count())) ? $consumables->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$allowed_columns = ['id', 'name', 'order_number', 'min_amt', 'purchase_date', 'purchase_cost', 'company', 'category', 'model_number', 'item_no', 'manufacturer', 'location', 'qty', 'image'];
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
@ -111,6 +112,9 @@ class ConsumablesController extends Controller
|
|||
case 'company':
|
||||
$consumables = $consumables->OrderCompany($order);
|
||||
break;
|
||||
case 'supplier':
|
||||
$components = $consumables->OrderSupplier($order);
|
||||
break;
|
||||
default:
|
||||
$consumables = $consumables->orderBy($column_sort, $order);
|
||||
break;
|
||||
|
@ -154,7 +158,7 @@ class ConsumablesController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', Consumable::class);
|
||||
$consumable = Consumable::findOrFail($id);
|
||||
$consumable = Consumable::with('users')->findOrFail($id);
|
||||
|
||||
return (new ConsumablesTransformer)->transformConsumable($consumable);
|
||||
}
|
||||
|
@ -253,33 +257,39 @@ class ConsumablesController extends Controller
|
|||
public function checkout(Request $request, $id)
|
||||
{
|
||||
// Check if the consumable exists
|
||||
if (is_null($consumable = Consumable::find($id))) {
|
||||
if (!$consumable = Consumable::with('users')->find($id)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.does_not_exist')));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $consumable);
|
||||
|
||||
if ($consumable->qty > 0) {
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($consumable->numRemaining() <= 0) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.checkout.unavailable')));
|
||||
\Log::debug('No enough remaining');
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
$assigned_to = $request->input('assigned_to');
|
||||
if (is_null($user = User::find($assigned_to))) {
|
||||
// Return error message
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
||||
}
|
||||
// Check if the user exists - @TODO: this should probably be handled via validation, not here??
|
||||
if (!$user = User::find($request->input('assigned_to'))) {
|
||||
// Return error message
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
|
||||
\Log::debug('No valid user');
|
||||
}
|
||||
|
||||
// Update the consumable data
|
||||
$consumable->assigned_to = e($assigned_to);
|
||||
// Update the consumable data
|
||||
$consumable->assigned_to = $request->input('assigned_to');
|
||||
|
||||
$consumable->users()->attach($consumable->id, [
|
||||
'consumable_id' => $consumable->id,
|
||||
'user_id' => $user->id,
|
||||
'assigned_to' => $assigned_to,
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
$consumable->users()->attach($consumable->id,
|
||||
[
|
||||
'consumable_id' => $consumable->id,
|
||||
'user_id' => $user->id,
|
||||
'assigned_to' => $request->input('assigned_to'),
|
||||
'note' => $request->input('note'),
|
||||
]
|
||||
);
|
||||
|
||||
// Log checkout event
|
||||
$logaction = $consumable->logCheckout(e($request->input('note')), $user);
|
||||
$logaction = $consumable->logCheckout($request->input('note'), $user);
|
||||
$data['log_id'] = $logaction->id;
|
||||
$data['eula'] = $consumable->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
|
@ -289,9 +299,7 @@ class ConsumablesController extends Controller
|
|||
$data['require_acceptance'] = $consumable->requireAcceptance();
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No consumables remaining'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
|
|||
use App\Http\Transformers\CustomFieldsetsTransformer;
|
||||
use App\Http\Transformers\CustomFieldsTransformer;
|
||||
use App\Models\CustomFieldset;
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Http\Request;
|
||||
use Redirect;
|
||||
use View;
|
||||
|
@ -94,6 +95,18 @@ class CustomFieldsetsController extends Controller
|
|||
$fieldset->fill($request->all());
|
||||
|
||||
if ($fieldset->save()) {
|
||||
// Sync fieldset with auto_add_to_fieldsets
|
||||
$fields = CustomField::select('id')->where('auto_add_to_fieldsets', '=', '1')->get();
|
||||
|
||||
if ($fields->count() > 0) {
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$field_ids[] = $field->id;
|
||||
}
|
||||
|
||||
$fieldset->fields()->sync($field_ids);
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.create.success')));
|
||||
}
|
||||
|
||||
|
|
|
@ -58,12 +58,9 @@ class DepartmentsController extends Controller
|
|||
$departments->where('location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($departments) && ($request->get('offset') > $departments->count())) ? $departments->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $departments->count()) ? $departments->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -28,12 +28,9 @@ class DepreciationsController extends Controller
|
|||
$depreciations = $depreciations->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($depreciations) && ($request->get('offset') > $depreciations->count())) ? $depreciations->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $depreciations->count()) ? $depreciations->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -35,12 +35,9 @@ class GroupsController extends Controller
|
|||
$groups->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($groups) && ($request->get('offset') > $groups->count())) ? $groups->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $groups->count()) ? $groups->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -160,7 +160,7 @@ class ImportController extends Controller
|
|||
// Run a backup immediately before processing
|
||||
if ($request->get('run-backup')) {
|
||||
\Log::debug('Backup manually requested via importer');
|
||||
Artisan::call('backup:run');
|
||||
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]);
|
||||
} else {
|
||||
\Log::debug('NO BACKUP requested via importer');
|
||||
}
|
||||
|
@ -193,6 +193,9 @@ class ImportController extends Controller
|
|||
case 'user':
|
||||
$redirectTo = 'users.index';
|
||||
break;
|
||||
case 'location':
|
||||
$redirectTo = 'locations.index';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($errors) { //Failure
|
||||
|
|
|
@ -39,8 +39,10 @@ class LicenseSeatsController extends Controller
|
|||
}
|
||||
|
||||
$total = $seats->count();
|
||||
$offset = (($seats) && (request('offset') >= $total)) ? 0 : request('offset', 0);
|
||||
$limit = request('limit', 50);
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $seats->count()) ? $seats->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$seats = $seats->skip($offset)->take($limit)->get();
|
||||
|
||||
|
|
|
@ -94,12 +94,9 @@ class LicensesController extends Controller
|
|||
$licenses->onlyTrashed();
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($licenses) && ($request->get('offset') > $licenses->count())) ? $licenses->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
|
|
|
@ -78,14 +78,15 @@ class LocationsController extends Controller
|
|||
$locations->where('locations.country', '=', $request->input('country'));
|
||||
}
|
||||
|
||||
$offset = (($locations) && (request('offset') > $locations->count())) ? $locations->count() : request('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
||||
|
||||
|
||||
switch ($request->input('sort')) {
|
||||
case 'parent':
|
||||
$locations->OrderParent($order);
|
||||
|
|
|
@ -23,10 +23,10 @@ class ManufacturersController extends Controller
|
|||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', Manufacturer::class);
|
||||
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
|
||||
$allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'warranty_lookup_url', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
|
||||
|
||||
$manufacturers = Manufacturer::select(
|
||||
['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'deleted_at']
|
||||
['id', 'name', 'url', 'support_url', 'warranty_lookup_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'deleted_at']
|
||||
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count');
|
||||
|
||||
if ($request->input('deleted') == 'true') {
|
||||
|
@ -49,6 +49,10 @@ class ManufacturersController extends Controller
|
|||
$manufacturers->where('support_url', '=', $request->input('support_url'));
|
||||
}
|
||||
|
||||
if ($request->filled('warranty_lookup_url')) {
|
||||
$manufacturers->where('warranty_lookup_url', '=', $request->input('warranty_lookup_url'));
|
||||
}
|
||||
|
||||
if ($request->filled('support_phone')) {
|
||||
$manufacturers->where('support_phone', '=', $request->input('support_phone'));
|
||||
}
|
||||
|
@ -57,12 +61,9 @@ class ManufacturersController extends Controller
|
|||
$manufacturers->where('support_email', '=', $request->input('support_email'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($manufacturers) && ($request->get('offset') > $manufacturers->count())) ? $manufacturers->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -29,8 +29,10 @@ class PredefinedKitsController extends Controller
|
|||
$kits = $kits->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
$offset = $request->input('offset', 0);
|
||||
$limit = $request->input('limit', 50);
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $kits->count()) ? $kits->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'desc' ? 'desc' : 'asc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'name';
|
||||
$kits->orderBy($sort, $order);
|
||||
|
|
|
@ -54,15 +54,15 @@ class ReportsController extends Controller
|
|||
'note',
|
||||
];
|
||||
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $actionlogs->count()) ? $actionlogs->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
|
||||
$offset = request('offset', 0);
|
||||
$total = $actionlogs->count();
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
|
||||
|
||||
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
|
||||
|
||||
return response()->json((new ActionlogsTransformer)->transformActionlogs($actionlogs, $total), 200, ['Content-Type' => 'application/json;charset=utf8'], JSON_UNESCAPED_UNICODE);
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api;
|
|||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\AssetsTransformer;
|
||||
use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Http\Transformers\StatuslabelsTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Statuslabel;
|
||||
|
@ -50,12 +51,9 @@ class StatuslabelsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($statuslabels) && ($request->get('offset') > $statuslabels->count())) ? $statuslabels->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $statuslabels->count()) ? $statuslabels->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
@ -294,4 +292,45 @@ class StatuslabelsController extends Controller
|
|||
|
||||
return '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a paginated collection for the select2 menus
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.1.1]
|
||||
* @see \App\Http\Transformers\SelectlistTransformer
|
||||
*/
|
||||
public function selectlist(Request $request)
|
||||
{
|
||||
|
||||
$this->authorize('view.selectlists');
|
||||
$statuslabels = Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('deployable', 'desc');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$statuslabels = $statuslabels->where('name', 'LIKE', '%'.$request->get('search').'%');
|
||||
}
|
||||
|
||||
if ($request->filled('deployable')) {
|
||||
$statuslabels = $statuslabels->where('deployable', '=', '1');
|
||||
}
|
||||
|
||||
if ($request->filled('pending')) {
|
||||
$statuslabels = $statuslabels->where('pending', '=', '1');
|
||||
}
|
||||
|
||||
if ($request->filled('archived')) {
|
||||
$statuslabels = $statuslabels->where('archived', '=', '1');
|
||||
}
|
||||
|
||||
$statuslabels = $statuslabels->orderBy('name', 'ASC')->paginate(50);
|
||||
|
||||
// Loop through and set some custom properties for the transformer to use.
|
||||
// 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 ($statuslabels as $statuslabel) {
|
||||
$statuslabels->use_text = $statuslabel->name;
|
||||
}
|
||||
|
||||
return (new SelectlistTransformer)->transformSelectlist($statuslabels);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,30 @@ 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', 'url'];
|
||||
$allowed_columns = ['
|
||||
id',
|
||||
'name',
|
||||
'address',
|
||||
'phone',
|
||||
'contact',
|
||||
'fax',
|
||||
'email',
|
||||
'image',
|
||||
'assets_count',
|
||||
'licenses_count',
|
||||
'accessories_count',
|
||||
'components_count',
|
||||
'consumables_count',
|
||||
'url',
|
||||
];
|
||||
|
||||
$suppliers = Supplier::select(
|
||||
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'updated_at', 'deleted_at', 'image', 'notes']
|
||||
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('accessories as accessories_count');
|
||||
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'updated_at', 'deleted_at', 'image', 'notes'])
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('licenses as licenses_count')
|
||||
->withCount('accessories as accessories_count')
|
||||
->withCount('components as components_count')
|
||||
->withCount('consumables as consumables_count');
|
||||
|
||||
|
||||
if ($request->filled('search')) {
|
||||
|
@ -74,12 +93,9 @@ class SuppliersController extends Controller
|
|||
$suppliers->where('notes', '=', $request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($suppliers) && ($request->get('offset') > $suppliers->count())) ? $suppliers->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $suppliers->count()) ? $suppliers->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
|
|
|
@ -71,6 +71,7 @@ class UsersController extends Controller
|
|||
'users.start_date',
|
||||
'users.end_date',
|
||||
'users.vip',
|
||||
'users.autoassign_licenses',
|
||||
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
|
||||
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
|
||||
|
@ -187,18 +188,19 @@ class UsersController extends Controller
|
|||
$users->has('accessories', '=', $request->input('accessories_count'));
|
||||
}
|
||||
|
||||
if ($request->filled('autoassign_licenses')) {
|
||||
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$users = $users->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($users) && ($request->get('offset') > $users->count())) ? $users->count() : $request->get('offset', 0);
|
||||
|
||||
// Check to make sure the limit is not higher than the max allowed
|
||||
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
|
||||
switch ($request->input('sort')) {
|
||||
|
@ -262,6 +264,7 @@ class UsersController extends Controller
|
|||
'vip',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'autoassign_licenses',
|
||||
];
|
||||
|
||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
||||
|
@ -359,7 +362,7 @@ class UsersController extends Controller
|
|||
$user->permissions = $permissions_array;
|
||||
}
|
||||
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
$user->password = bcrypt($request->get('password', $tmp_pass));
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
|
|
|
@ -101,7 +101,7 @@ class AssetMaintenancesController extends Controller
|
|||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
|
||||
$assetMaintenance->cost = $request->input('cost');
|
||||
$assetMaintenance->notes = $request->input('notes');
|
||||
$asset = Asset::find($request->input('asset_id'));
|
||||
|
||||
|
@ -211,7 +211,7 @@ class AssetMaintenancesController extends Controller
|
|||
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||
$assetMaintenance->cost = Helper::ParseCurrency($request->input('cost'));
|
||||
$assetMaintenance->cost = $request->input('cost');
|
||||
$assetMaintenance->notes = $request->input('notes');
|
||||
|
||||
$asset = Asset::find(request('asset_id'));
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Models\CheckoutRequest;
|
|||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
|
@ -140,9 +141,9 @@ class AssetsController extends Controller
|
|||
$asset->depreciate = '0';
|
||||
$asset->status_id = request('status_id');
|
||||
$asset->warranty_months = request('warranty_months', null);
|
||||
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
|
||||
$asset->purchase_cost = request('purchase_cost');
|
||||
$asset->purchase_date = request('purchase_date', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', $asset->present()->eol_date());
|
||||
$asset->assigned_to = request('assigned_to', null);
|
||||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
|
@ -312,7 +313,7 @@ class AssetsController extends Controller
|
|||
|
||||
$asset->status_id = $request->input('status_id', null);
|
||||
$asset->warranty_months = $request->input('warranty_months', null);
|
||||
$asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
|
||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
|
@ -324,6 +325,12 @@ class AssetsController extends Controller
|
|||
$asset->rtd_location_id = $request->input('rtd_location_id', null);
|
||||
$asset->byod = $request->input('byod', 0);
|
||||
|
||||
$status = Statuslabel::find($asset->status_id);
|
||||
|
||||
if($status->archived){
|
||||
$asset->assigned_to = null;
|
||||
}
|
||||
|
||||
if ($asset->assigned_to == '') {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@ class BulkAssetsController extends Controller
|
|||
{
|
||||
// dd($request->all());
|
||||
// dd(Session::get('ids'));
|
||||
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
|
||||
$this->authorize('view', Asset::class);
|
||||
|
||||
if (! $request->filled('ids')) {
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||
}
|
||||
|
@ -68,19 +68,33 @@ class BulkAssetsController extends Controller
|
|||
if ($request->filled('bulk_actions')) {
|
||||
switch ($request->input('bulk_actions')) {
|
||||
case 'labels':
|
||||
$this->authorize('view', Asset::class);
|
||||
return view('hardware/labels')
|
||||
->with('assets', Asset::find($asset_ids))
|
||||
->with('settings', Setting::getSettings())
|
||||
->with('bulkedit', true)
|
||||
->with('count', 0);
|
||||
|
||||
case 'delete':
|
||||
$this->authorize('delete', Asset::class);
|
||||
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('delete', $asset);
|
||||
});
|
||||
|
||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||
|
||||
case 'restore':
|
||||
$this->authorize('update', Asset::class);
|
||||
$assets = Asset::withTrashed()->find($asset_ids);
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('delete', $asset);
|
||||
});
|
||||
|
||||
return view('hardware/bulk-restore')->with('assets', $assets);
|
||||
|
||||
case 'edit':
|
||||
$this->authorize('update', Asset::class);
|
||||
return view('hardware/bulk')
|
||||
->with('assets', $asset_ids)
|
||||
->with('statuslabel_list', Helper::statusLabelList())
|
||||
|
@ -178,7 +192,7 @@ class BulkAssetsController extends Controller
|
|||
}
|
||||
|
||||
if ($request->filled('purchase_cost')) {
|
||||
$this->update_array['purchase_cost'] = Helper::ParseCurrency($request->input('purchase_cost'));
|
||||
$this->update_array['purchase_cost'] = $request->input('purchase_cost');
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
|
@ -399,5 +413,19 @@ class BulkAssetsController extends Controller
|
|||
} catch (ModelNotFoundException $e) {
|
||||
return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors());
|
||||
}
|
||||
|
||||
}
|
||||
public function restore(Request $request) {
|
||||
$this->authorize('update', Asset::class);
|
||||
$assetIds = $request->get('ids');
|
||||
if (empty($assetIds)) {
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
|
||||
} else {
|
||||
foreach ($assetIds as $key => $assetId) {
|
||||
$asset = Asset::withTrashed()->find($assetId);
|
||||
$asset->restore();
|
||||
}
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ class BulkAssetModelsController extends Controller
|
|||
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
|
||||
|
||||
return redirect()->route('models.index')
|
||||
->with('success', trans('admin/models/message.bulkedit.success'));
|
||||
->with('success', trans_choice('admin/models/message.bulkedit.success', count($models_raw_array), ['model_count' => count($models_raw_array)]));
|
||||
}
|
||||
|
||||
return redirect()->route('models.index')
|
||||
|
|
|
@ -33,6 +33,11 @@ class ComponentCheckoutController extends Controller
|
|||
}
|
||||
$this->authorize('checkout', $component);
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($component->numRemaining() <= 0){
|
||||
return redirect()->route('components.index')->with('error', trans('admin/components/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
return view('components/checkout', compact('component'));
|
||||
}
|
||||
|
||||
|
@ -50,7 +55,7 @@ class ComponentCheckoutController extends Controller
|
|||
public function store(Request $request, $componentId)
|
||||
{
|
||||
// Check if the component exists
|
||||
if (is_null($component = Component::find($componentId))) {
|
||||
if (!$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'));
|
||||
}
|
||||
|
@ -58,9 +63,15 @@ class ComponentCheckoutController extends Controller
|
|||
$this->authorize('checkout', $component);
|
||||
|
||||
$max_to_checkout = $component->numRemaining();
|
||||
|
||||
// Make sure there are at least the requested number of components available to checkout
|
||||
if ($max_to_checkout < $request->get('assigned_qty')) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/components/message.checkout.unavailable', ['remaining' => $max_to_checkout, 'requested' => $request->get('assigned_qty')]));
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'asset_id' => 'required',
|
||||
'assigned_qty' => "required|numeric|between:1,$max_to_checkout",
|
||||
'asset_id' => 'required|exists:assets,id',
|
||||
'assigned_qty' => "required|numeric|min:1|digits_between:1,$max_to_checkout",
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
|
@ -69,24 +80,17 @@ class ComponentCheckoutController extends Controller
|
|||
->withInput();
|
||||
}
|
||||
|
||||
$admin_user = Auth::user();
|
||||
$asset_id = e($request->input('asset_id'));
|
||||
|
||||
// Check if the user exists
|
||||
if (is_null($asset = Asset::find($asset_id))) {
|
||||
// Redirect to the component management page with error
|
||||
return redirect()->route('components.index')->with('error', trans('admin/components/message.asset_does_not_exist'));
|
||||
}
|
||||
$asset = Asset::find($request->input('asset_id'));
|
||||
|
||||
// Update the component data
|
||||
$component->asset_id = $asset_id;
|
||||
|
||||
$component->asset_id = $request->input('asset_id');
|
||||
$component->assets()->attach($component->id, [
|
||||
'component_id' => $component->id,
|
||||
'user_id' => $admin_user->id,
|
||||
'user_id' => Auth::user(),
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'assigned_qty' => $request->input('assigned_qty'),
|
||||
'asset_id' => $asset_id,
|
||||
'asset_id' => $request->input('asset_id'),
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
|
|
|
@ -71,13 +71,14 @@ class ComponentsController extends Controller
|
|||
$component = new Component();
|
||||
$component->name = $request->input('name');
|
||||
$component->category_id = $request->input('category_id');
|
||||
$component->supplier_id = $request->input('supplier_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 = Helper::ParseCurrency($request->input('purchase_cost', null));
|
||||
$component->purchase_cost = $request->input('purchase_cost', null);
|
||||
$component->qty = $request->input('qty');
|
||||
$component->user_id = Auth::id();
|
||||
$component->notes = $request->input('notes');
|
||||
|
@ -145,13 +146,14 @@ class ComponentsController extends Controller
|
|||
// Update the component data
|
||||
$component->name = $request->input('name');
|
||||
$component->category_id = $request->input('category_id');
|
||||
$component->supplier_id = $request->input('supplier_id');
|
||||
$component->location_id = $request->input('location_id');
|
||||
$component->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$component->order_number = $request->input('order_number');
|
||||
$component->min_amt = $request->input('min_amt');
|
||||
$component->serial = $request->input('serial');
|
||||
$component->purchase_date = $request->input('purchase_date');
|
||||
$component->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
|
||||
$component->purchase_cost = request('purchase_cost');
|
||||
$component->qty = $request->input('qty');
|
||||
$component->notes = $request->input('notes');
|
||||
|
||||
|
|
|
@ -24,9 +24,16 @@ class ConsumableCheckoutController extends Controller
|
|||
*/
|
||||
public function create($consumableId)
|
||||
{
|
||||
if (is_null($consumable = Consumable::find($consumableId))) {
|
||||
|
||||
if (is_null($consumable = Consumable::with('users')->find($consumableId))) {
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
|
||||
}
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($consumable->numRemaining() <= 0){
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $consumable);
|
||||
|
||||
return view('consumables/checkout', compact('consumable'));
|
||||
|
@ -44,12 +51,18 @@ class ConsumableCheckoutController extends Controller
|
|||
*/
|
||||
public function store(Request $request, $consumableId)
|
||||
{
|
||||
if (is_null($consumable = Consumable::find($consumableId))) {
|
||||
if (is_null($consumable = Consumable::with('users')->find($consumableId))) {
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $consumable);
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($consumable->numRemaining() <= 0) {
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||
}
|
||||
|
||||
|
||||
$admin_user = Auth::user();
|
||||
$assigned_to = e($request->input('assigned_to'));
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ class ConsumablesController extends Controller
|
|||
$consumable = new Consumable();
|
||||
$consumable->name = $request->input('name');
|
||||
$consumable->category_id = $request->input('category_id');
|
||||
$consumable->supplier_id = $request->input('supplier_id');
|
||||
$consumable->location_id = $request->input('location_id');
|
||||
$consumable->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$consumable->order_number = $request->input('order_number');
|
||||
|
@ -76,7 +77,7 @@ class ConsumablesController extends Controller
|
|||
$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::ParseCurrency($request->input('purchase_cost'));
|
||||
$consumable->purchase_cost = $request->input('purchase_cost');
|
||||
$consumable->qty = $request->input('qty');
|
||||
$consumable->user_id = Auth::id();
|
||||
$consumable->notes = $request->input('notes');
|
||||
|
@ -144,6 +145,7 @@ class ConsumablesController extends Controller
|
|||
|
||||
$consumable->name = $request->input('name');
|
||||
$consumable->category_id = $request->input('category_id');
|
||||
$consumable->supplier_id = $request->input('supplier_id');
|
||||
$consumable->location_id = $request->input('location_id');
|
||||
$consumable->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$consumable->order_number = $request->input('order_number');
|
||||
|
@ -152,7 +154,7 @@ class ConsumablesController extends Controller
|
|||
$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::ParseCurrency($request->input('purchase_cost'));
|
||||
$consumable->purchase_cost = $request->input('purchase_cost');
|
||||
$consumable->qty = Helper::ParseFloat($request->input('qty'));
|
||||
$consumable->notes = $request->input('notes');
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
*
|
||||
* **THIS DOCUMENTATION DOES NOT COVER INSTALLATION.** If you're here and you're not a
|
||||
* developer, you're probably in the wrong place. Please see the
|
||||
* [Installation documentation](http://docs.snipeitapp.com) for
|
||||
* [Installation documentation](https://snipe-it.readme.io) for
|
||||
* information on how to install Snipe-IT.
|
||||
*
|
||||
* To learn how to set up a development environment and get started developing for Snipe-IT,
|
||||
* please see the [contributing documentation](http://docs.snipeitapp.com/contributing.html).
|
||||
* please see the [contributing documentation](https://snipe-it.readme.io/docs/contributing-overview).
|
||||
*
|
||||
* Only the Snipe-IT specific controllers, models, helpers, service providers,
|
||||
* etc have been included in this documentation (excluding vendors, Laravel core, etc)
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Http\Requests\CustomFieldRequest;
|
|||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Redirect;
|
||||
|
||||
/**
|
||||
|
@ -45,7 +46,7 @@ class CustomFieldsController extends Controller
|
|||
* @see CustomFieldsController::storeField()
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.1.5]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show()
|
||||
|
@ -63,14 +64,17 @@ class CustomFieldsController extends Controller
|
|||
* @return \Illuminate\Support\Facades\View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function create()
|
||||
public function create(Request $request)
|
||||
{
|
||||
$this->authorize('create', CustomField::class);
|
||||
$fieldsets = CustomFieldset::get();
|
||||
|
||||
return view('custom_fields.fields.edit', [
|
||||
'predefinedFormats' => Helper::predefined_formats(),
|
||||
'customFormat' => '',
|
||||
])->with('field', new CustomField());
|
||||
'customFormat' => '',
|
||||
'fieldsets' => $fieldsets,
|
||||
'field' => new CustomField(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +83,7 @@ class CustomFieldsController extends Controller
|
|||
* @see CustomFieldsController::createField()
|
||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||
* @since [v1.8]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(CustomFieldRequest $request)
|
||||
|
@ -104,6 +108,7 @@ class CustomFieldsController extends Controller
|
|||
"show_in_email" => $show_in_email,
|
||||
"is_unique" => $request->get("is_unique", 0),
|
||||
"display_in_user_view" => $display_in_user_view,
|
||||
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
|
||||
"user_id" => Auth::id()
|
||||
]);
|
||||
|
||||
|
@ -115,10 +120,20 @@ class CustomFieldsController extends Controller
|
|||
}
|
||||
|
||||
if ($field->save()) {
|
||||
|
||||
// Sync fields with fieldsets
|
||||
$fieldset_array = $request->input('associate_fieldsets');
|
||||
if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) {
|
||||
$field->fieldset()->sync(array_keys($fieldset_array));
|
||||
} else {
|
||||
$field->fieldset()->sync([]);
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.create.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()
|
||||
return redirect()->back()->with('selected_fieldsets', $request->input('associate_fieldsets'))->withInput()
|
||||
->with('error', trans('admin/custom_fields/message.field.create.error'));
|
||||
}
|
||||
|
||||
|
@ -128,7 +143,7 @@ class CustomFieldsController extends Controller
|
|||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function deleteFieldFromFieldset($field_id, $fieldset_id)
|
||||
|
@ -147,8 +162,7 @@ class CustomFieldsController extends Controller
|
|||
->with('success', trans('admin/custom_fields/message.field.delete.success'));
|
||||
} else {
|
||||
return redirect()->back()->withErrors(['message' => "Field is in use and cannot be deleted."]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back()->withErrors(['message' => "Error deleting field from fieldset"]);
|
||||
|
@ -161,7 +175,7 @@ class CustomFieldsController extends Controller
|
|||
*
|
||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||
* @since [v1.8]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($field_id)
|
||||
|
@ -190,12 +204,12 @@ class CustomFieldsController extends Controller
|
|||
* @return \Illuminate\Support\Facades\View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function edit($id)
|
||||
public function edit(Request $request, $id)
|
||||
{
|
||||
if ($field = CustomField::find($id)) {
|
||||
|
||||
$this->authorize('update', $field);
|
||||
|
||||
$fieldsets = CustomFieldset::get();
|
||||
$customFormat = '';
|
||||
if ((stripos($field->format, 'regex') === 0) && ($field->format !== CustomField::PREDEFINED_FORMATS['MAC'])) {
|
||||
$customFormat = $field->format;
|
||||
|
@ -204,6 +218,7 @@ class CustomFieldsController extends Controller
|
|||
return view('custom_fields.fields.edit', [
|
||||
'field' => $field,
|
||||
'customFormat' => $customFormat,
|
||||
'fieldsets' => $fieldsets,
|
||||
'predefinedFormats' => Helper::predefined_formats(),
|
||||
]);
|
||||
}
|
||||
|
@ -222,7 +237,7 @@ class CustomFieldsController extends Controller
|
|||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $id
|
||||
* @since [v4.0]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function update(CustomFieldRequest $request, $id)
|
||||
|
@ -249,6 +264,7 @@ class CustomFieldsController extends Controller
|
|||
$field->show_in_email = $show_in_email;
|
||||
$field->is_unique = $request->get("is_unique", 0);
|
||||
$field->display_in_user_view = $display_in_user_view;
|
||||
$field->auto_add_to_fieldsets = $request->get("auto_add_to_fieldsets", 0);
|
||||
|
||||
if ($request->get('format') == 'CUSTOM REGEX') {
|
||||
$field->format = e($request->get('custom_format'));
|
||||
|
@ -256,11 +272,21 @@ class CustomFieldsController extends Controller
|
|||
$field->format = e($request->get('format'));
|
||||
}
|
||||
|
||||
if($field->element == 'checkbox' || $field->element == 'radio'){
|
||||
if ($field->element == 'checkbox' || $field->element == 'radio'){
|
||||
$field->format = 'ANY';
|
||||
}
|
||||
|
||||
if ($field->save()) {
|
||||
|
||||
|
||||
// Sync fields with fieldsets
|
||||
$fieldset_array = $request->input('associate_fieldsets');
|
||||
if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) {
|
||||
$field->fieldset()->sync(array_keys($fieldset_array));
|
||||
} else {
|
||||
$field->fieldset()->sync([]);
|
||||
}
|
||||
|
||||
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.update.success'));
|
||||
}
|
||||
|
||||
|
|
|
@ -93,16 +93,27 @@ class CustomFieldsetsController extends Controller
|
|||
{
|
||||
$this->authorize('create', CustomField::class);
|
||||
|
||||
$cfset = new CustomFieldset([
|
||||
$fieldset = new CustomFieldset([
|
||||
'name' => e($request->get('name')),
|
||||
'user_id' => Auth::user()->id,
|
||||
]);
|
||||
|
||||
$validator = Validator::make($request->all(), $cfset->rules);
|
||||
if ($validator->passes()) {
|
||||
$cfset->save();
|
||||
$validator = Validator::make($request->all(), $fieldset->rules);
|
||||
|
||||
return redirect()->route('fieldsets.show', [$cfset->id])
|
||||
if ($validator->passes()) {
|
||||
$fieldset->save();
|
||||
|
||||
// Sync fieldset with auto_add_to_fieldsets
|
||||
$fields = CustomField::select('id')->where('auto_add_to_fieldsets', '=', '1')->get();
|
||||
if ($fields->count() > 0) {
|
||||
foreach ($fields as $field) {
|
||||
$field_ids[] = $field->id;
|
||||
}
|
||||
|
||||
$fieldset->fields()->sync($field_ids);
|
||||
}
|
||||
|
||||
return redirect()->route('fieldsets.show', [$fieldset->id])
|
||||
->with('success', trans('admin/custom_fields/message.fieldset.create.success'));
|
||||
}
|
||||
|
||||
|
|
74
app/Http/Controllers/GoogleAuthController.php
Normal file
74
app/Http/Controllers/GoogleAuthController.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
use Laravel\Socialite\Two\InvalidStateException;
|
||||
use App\Models\Setting;
|
||||
|
||||
|
||||
class GoogleAuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* We need this constructor so that we override the socialite expected config variables,
|
||||
* since we want to allow this to be changed via database fields
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$setting = Setting::getSettings();
|
||||
config(['services.google.redirect' => config('app.url').'/google/callback']);
|
||||
config(['services.google.client_id' => $setting->google_client_id]);
|
||||
config(['services.google.client_secret' => $setting->google_client_secret]);
|
||||
}
|
||||
|
||||
public function redirectToGoogle()
|
||||
{
|
||||
return Socialite::driver('google')->redirect();
|
||||
}
|
||||
|
||||
public function handleGoogleCallback()
|
||||
{
|
||||
try {
|
||||
$socialUser = Socialite::driver('google')->user();
|
||||
\Log::debug('Google user found in Google Workspace');
|
||||
} catch (InvalidStateException $exception) {
|
||||
\Log::debug('Google user NOT found in Google Workspace');
|
||||
return redirect()->route('login')
|
||||
->withErrors(
|
||||
[
|
||||
'username' => [
|
||||
trans('auth/general.google_login_failed')
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$user = User::where('username', $socialUser->getEmail())->first();
|
||||
|
||||
|
||||
if ($user) {
|
||||
\Log::debug('Google user '.$socialUser->getEmail().' found in Snipe-IT');
|
||||
$user->update([
|
||||
'avatar' => $socialUser->avatar,
|
||||
]);
|
||||
|
||||
Auth::login($user, true);
|
||||
return redirect()->route('home');
|
||||
}
|
||||
|
||||
\Log::debug('Google user '.$socialUser->getEmail().' NOT found in Snipe-IT');
|
||||
return redirect()->route('login')
|
||||
->withErrors(
|
||||
[
|
||||
'username' => [
|
||||
trans('auth/general.google_login_failed'),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -92,7 +92,7 @@ class GroupsController extends Controller
|
|||
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
|
||||
}
|
||||
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found'));
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,7 @@ class GroupsController extends Controller
|
|||
public function update(Request $request, $id = null)
|
||||
{
|
||||
if (! $group = Group::find($id)) {
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
|
||||
}
|
||||
$group->name = $request->input('name');
|
||||
$group->permissions = json_encode($request->input('permission'));
|
||||
|
@ -133,14 +133,13 @@ class GroupsController extends Controller
|
|||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy($id = null)
|
||||
public function destroy($id)
|
||||
{
|
||||
if (! config('app.lock_passwords')) {
|
||||
if (! $group = Group::find($id)) {
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
|
||||
}
|
||||
$group->delete();
|
||||
// Redirect to the group management page
|
||||
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.delete'));
|
||||
}
|
||||
|
||||
|
@ -164,6 +163,6 @@ class GroupsController extends Controller
|
|||
return view('groups/view', compact('group'));
|
||||
}
|
||||
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
|
||||
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,4 +112,54 @@ class LicenseCheckinController extends Controller
|
|||
// Redirect to the license page with error
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkin.error'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk checkin all license seats
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see LicenseCheckinController::create() method that provides the form view
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
|
||||
public function bulkCheckin(Request $request, $licenseId) {
|
||||
|
||||
$license = License::findOrFail($licenseId);
|
||||
$this->authorize('checkin', $license);
|
||||
|
||||
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
||||
->whereNotNull('assigned_to')
|
||||
->with('user')
|
||||
->get();
|
||||
|
||||
foreach ($licenseSeatsByUser as $user_seat) {
|
||||
$user_seat->assigned_to = null;
|
||||
|
||||
if ($user_seat->save()) {
|
||||
\Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
|
||||
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||
}
|
||||
}
|
||||
|
||||
$licenseSeatsByAsset = LicenseSeat::where('license_id', '=', $licenseId)
|
||||
->whereNotNull('asset_id')
|
||||
->with('asset')
|
||||
->get();
|
||||
|
||||
$count = 0;
|
||||
foreach ($licenseSeatsByAsset as $asset_seat) {
|
||||
$asset_seat->asset_id = null;
|
||||
|
||||
if ($asset_seat->save()) {
|
||||
\Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
|
||||
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', trans_choice('admin/licenses/general.bulk.checkin_all.success', 2, ['count' => $count] ));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -126,4 +126,70 @@ class LicenseCheckoutController extends Controller
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk checkin all license seats
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see LicenseCheckinController::create() method that provides the form view
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
|
||||
public function bulkCheckout($licenseId) {
|
||||
|
||||
\Log::debug('Checking out '.$licenseId.' via bulk');
|
||||
$license = License::findOrFail($licenseId);
|
||||
$this->authorize('checkin', $license);
|
||||
$avail_count = $license->getAvailSeatsCountAttribute();
|
||||
|
||||
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '=', 1)->with('licenses')->get();
|
||||
\Log::debug($avail_count.' will be assigned');
|
||||
|
||||
if ($users->count() > $avail_count) {
|
||||
\Log::debug('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
|
||||
}
|
||||
|
||||
// If the license is valid, check that there is an available seat
|
||||
if ($license->availCount()->count() < 1) {
|
||||
return redirect()->back()->with('error', trans('admin/licenses/general.bulk.checkout_all.error_no_seats'));
|
||||
}
|
||||
|
||||
|
||||
$assigned_count = 0;
|
||||
|
||||
foreach ($users as $user) {
|
||||
|
||||
// Check to make sure this user doesn't already have this license checked out to them
|
||||
if ($user->licenses->where('id', '=', $licenseId)->count()) {
|
||||
\Log::debug($user->username.' already has this license checked out to them. Skipping... ');
|
||||
continue;
|
||||
}
|
||||
|
||||
$licenseSeat = $license->freeSeat();
|
||||
|
||||
// Update the seat with checkout info
|
||||
$licenseSeat->assigned_to = $user->id;
|
||||
|
||||
if ($licenseSeat->save()) {
|
||||
$avail_count--;
|
||||
$assigned_count++;
|
||||
$licenseSeat->logCheckout(trans('admin/licenses/general.bulk.checkout_all.log_msg'), $user);
|
||||
\Log::debug('License '.$license->name.' seat '.$licenseSeat->id.' checked out to '.$user->username);
|
||||
}
|
||||
|
||||
if ($avail_count == 0) {
|
||||
return redirect()->back()->with('warning', trans('admin/licenses/general.bulk.checkout_all.warn_not_enough_seats', ['count' => $assigned_count]));
|
||||
}
|
||||
}
|
||||
|
||||
if ($assigned_count == 0) {
|
||||
return redirect()->back()->with('warning', trans('admin/licenses/general.bulk.checkout_all.warn_no_avail_users', ['count' => $assigned_count]));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', trans_choice('admin/licenses/general.bulk.checkout_all.success', 2, ['count' => $assigned_count] ));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use App\Helpers\Helper;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
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\DB;
|
||||
|
@ -86,7 +88,7 @@ class LicensesController extends Controller
|
|||
$license->name = $request->input('name');
|
||||
$license->notes = $request->input('notes');
|
||||
$license->order_number = $request->input('order_number');
|
||||
$license->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
|
||||
$license->purchase_cost = $request->input('purchase_cost');
|
||||
$license->purchase_date = $request->input('purchase_date');
|
||||
$license->purchase_order = $request->input('purchase_order');
|
||||
$license->purchase_order = $request->input('purchase_order');
|
||||
|
@ -164,7 +166,7 @@ class LicensesController extends Controller
|
|||
$license->name = $request->input('name');
|
||||
$license->notes = $request->input('notes');
|
||||
$license->order_number = $request->input('order_number');
|
||||
$license->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
|
||||
$license->purchase_cost = $request->input('purchase_cost');
|
||||
$license->purchase_date = $request->input('purchase_date');
|
||||
$license->purchase_order = $request->input('purchase_order');
|
||||
$license->reassignable = $request->input('reassignable', 0);
|
||||
|
@ -233,16 +235,40 @@ class LicensesController extends Controller
|
|||
{
|
||||
$license = License::with('assignedusers')->find($licenseId);
|
||||
|
||||
if ($license) {
|
||||
$this->authorize('view', $license);
|
||||
|
||||
return view('licenses/view', compact('license'));
|
||||
if (!$license) {
|
||||
return redirect()->route('licenses.index')
|
||||
->with('error', trans('admin/licenses/message.does_not_exist'));
|
||||
}
|
||||
|
||||
return redirect()->route('licenses.index')
|
||||
->with('error', trans('admin/licenses/message.does_not_exist'));
|
||||
$users_count = User::where('autoassign_licenses', '1')->count();
|
||||
$total_seats_count = $license->totalSeatsByLicenseID();
|
||||
$available_seats_count = $license->availCount()->count();
|
||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
||||
|
||||
\Log::debug('Total: '.$total_seats_count);
|
||||
\Log::debug('Users: '.$users_count);
|
||||
\Log::debug('Available: '.$available_seats_count);
|
||||
\Log::debug('Checkedout: '.$checkedout_seats_count);
|
||||
|
||||
|
||||
$this->authorize('view', $license);
|
||||
return view('licenses.view', compact('license'))
|
||||
->with('users_count', $users_count)
|
||||
->with('total_seats_count', $total_seats_count)
|
||||
->with('available_seats_count', $available_seats_count)
|
||||
->with('checkedout_seats_count', $checkedout_seats_count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a view with prepopulated data for clone
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $licenseId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function getClone($licenseId = null)
|
||||
{
|
||||
if (is_null($license_to_clone = License::find($licenseId))) {
|
||||
|
|
|
@ -68,6 +68,7 @@ class ManufacturersController extends Controller
|
|||
$manufacturer->user_id = Auth::id();
|
||||
$manufacturer->url = $request->input('url');
|
||||
$manufacturer->support_url = $request->input('support_url');
|
||||
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
|
||||
$manufacturer->support_phone = $request->input('support_phone');
|
||||
$manufacturer->support_email = $request->input('support_email');
|
||||
$manufacturer = $request->handleImages($manufacturer);
|
||||
|
@ -123,10 +124,11 @@ class ManufacturersController extends Controller
|
|||
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist'));
|
||||
}
|
||||
|
||||
// Save the data
|
||||
// Save the data
|
||||
$manufacturer->name = $request->input('name');
|
||||
$manufacturer->url = $request->input('url');
|
||||
$manufacturer->support_url = $request->input('support_url');
|
||||
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
|
||||
$manufacturer->support_phone = $request->input('support_phone');
|
||||
$manufacturer->support_email = $request->input('support_email');
|
||||
|
||||
|
|
|
@ -595,23 +595,23 @@ class ReportsController extends Controller
|
|||
'model.category', 'model.manufacturer', 'supplier');
|
||||
|
||||
if ($request->filled('by_location_id')) {
|
||||
$assets->where('assets.location_id', $request->input('by_location_id'));
|
||||
$assets->whereIn('assets.location_id', $request->input('by_location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('by_rtd_location_id')) {
|
||||
$assets->where('assets.rtd_location_id', $request->input('by_rtd_location_id'));
|
||||
$assets->whereIn('assets.rtd_location_id', $request->input('by_rtd_location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('by_supplier_id')) {
|
||||
$assets->where('assets.supplier_id', $request->input('by_supplier_id'));
|
||||
$assets->whereIn('assets.supplier_id', $request->input('by_supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('by_company_id')) {
|
||||
$assets->where('assets.company_id', $request->input('by_company_id'));
|
||||
$assets->whereIn('assets.company_id', $request->input('by_company_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('by_model_id')) {
|
||||
$assets->where('assets.model_id', $request->input('by_model_id'));
|
||||
$assets->whereIn('assets.model_id', $request->input('by_model_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('by_category_id')) {
|
||||
|
@ -631,7 +631,7 @@ class ReportsController extends Controller
|
|||
}
|
||||
|
||||
if ($request->filled('by_status_id')) {
|
||||
$assets->where('assets.status_id', $request->input('by_status_id'));
|
||||
$assets->whereIn('assets.status_id', $request->input('by_status_id'));
|
||||
}
|
||||
|
||||
if (($request->filled('purchase_start')) && ($request->filled('purchase_end'))) {
|
||||
|
@ -641,6 +641,9 @@ class ReportsController extends Controller
|
|||
if (($request->filled('created_start')) && ($request->filled('created_end'))) {
|
||||
$assets->whereBetween('assets.created_at', [$request->input('created_start'), $request->input('created_end')]);
|
||||
}
|
||||
if (($request->filled('checkout_date_start')) && ($request->filled('checkout_date_end'))) {
|
||||
$assets->whereBetween('assets.last_checkout', [$request->input('checkout_date_start'), $request->input('checkout_date_end')]);
|
||||
}
|
||||
|
||||
if (($request->filled('expected_checkin_start')) && ($request->filled('expected_checkin_end'))) {
|
||||
$assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]);
|
||||
|
@ -663,6 +666,7 @@ class ReportsController extends Controller
|
|||
$assets->onlyTrashed();
|
||||
}
|
||||
|
||||
\Log::debug($assets->toSql());
|
||||
$assets->orderBy('assets.id', 'ASC')->chunk(20, function ($assets) use ($handle, $customfields, $request) {
|
||||
|
||||
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
|
||||
|
@ -898,12 +902,8 @@ class ReportsController extends Controller
|
|||
public function getAssetMaintenancesReport()
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
// Grab all the improvements
|
||||
$assetMaintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
|
||||
return view('reports/asset_maintenances', compact('assetMaintenances'));
|
||||
return view('reports.asset_maintenances');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -84,7 +84,7 @@ class SettingsController extends Controller
|
|||
}
|
||||
$pageURL = $protocol.$host.$_SERVER['REQUEST_URI'];
|
||||
|
||||
$start_settings['url_config'] = url('/').'/setup';
|
||||
$start_settings['url_config'] = config('app.url').'/setup';
|
||||
$start_settings['url_valid'] = ($start_settings['url_config'] === $pageURL);
|
||||
$start_settings['real_url'] = $pageURL;
|
||||
$start_settings['php_version_min'] = true;
|
||||
|
@ -961,6 +961,7 @@ class SettingsController extends Controller
|
|||
$setting->ldap_phone_field = $request->input('ldap_phone');
|
||||
$setting->ldap_jobtitle = $request->input('ldap_jobtitle');
|
||||
$setting->ldap_country = $request->input('ldap_country');
|
||||
$setting->ldap_location = $request->input('ldap_location');
|
||||
$setting->ldap_dept = $request->input('ldap_dept');
|
||||
$setting->ldap_client_tls_cert = $request->input('ldap_client_tls_cert');
|
||||
$setting->ldap_client_tls_key = $request->input('ldap_client_tls_key');
|
||||
|
@ -1038,6 +1039,48 @@ class SettingsController extends Controller
|
|||
return $pdf_branding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show Google login settings form
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.1.1]
|
||||
* @return View
|
||||
*/
|
||||
public function getGoogleLoginSettings()
|
||||
{
|
||||
$setting = Setting::getSettings();
|
||||
return view('settings.google', compact('setting'));
|
||||
}
|
||||
|
||||
/**
|
||||
* ShSaveow Google login settings form
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.1.1]
|
||||
* @return View
|
||||
*/
|
||||
public function postGoogleLoginSettings(Request $request)
|
||||
{
|
||||
if (!config('app.lock_passwords')) {
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
$setting->google_login = $request->input('google_login', 0);
|
||||
$setting->google_client_id = $request->input('google_client_id');
|
||||
$setting->google_client_secret = $request->input('google_client_secret');
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
->with('success', trans('admin/settings/message.update.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($setting->getErrors());
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the listing of backups.
|
||||
*
|
||||
|
@ -1093,7 +1136,7 @@ class SettingsController extends Controller
|
|||
public function postBackups()
|
||||
{
|
||||
if (! config('app.lock_passwords')) {
|
||||
Artisan::call('backup:run');
|
||||
Artisan::call('snipeit:backup', ['--filename' => 'manual-backup-'.date('Y-m-d-H:i:s')]);
|
||||
$output = Artisan::output();
|
||||
|
||||
// Backup completed
|
||||
|
|
|
@ -113,7 +113,8 @@ class BulkUsersController extends Controller
|
|||
->conditionallyAddItem('locale')
|
||||
->conditionallyAddItem('remote')
|
||||
->conditionallyAddItem('ldap_import')
|
||||
->conditionallyAddItem('activated');
|
||||
->conditionallyAddItem('activated')
|
||||
->conditionallyAddItem('autoassign_licenses');
|
||||
|
||||
|
||||
// If the manager_id is one of the users being updated, generate a warning.
|
||||
|
|
|
@ -74,7 +74,6 @@ class UsersController extends Controller
|
|||
$permissions = $this->filterDisplayable($permissions);
|
||||
|
||||
$user = new User;
|
||||
$user->activated = 1;
|
||||
|
||||
return view('users/edit', compact('groups', 'userGroups', 'permissions', 'userPermissions'))
|
||||
->with('user', $user);
|
||||
|
@ -121,7 +120,7 @@ class UsersController extends Controller
|
|||
$user->created_by = Auth::user()->id;
|
||||
$user->start_date = $request->input('start_date', null);
|
||||
$user->end_date = $request->input('end_date', null);
|
||||
$user->autoassign_licenses= $request->input('autoassign_licenses', 1);
|
||||
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
$permissions_array = $request->input('permission');
|
||||
|
@ -211,7 +210,6 @@ class UsersController extends Controller
|
|||
*/
|
||||
public function update(SaveUserRequest $request, $id = null)
|
||||
{
|
||||
|
||||
// We need to reverse the UI specific logic for our
|
||||
// permissions here before we update the user.
|
||||
$permissions = $request->input('permissions', []);
|
||||
|
@ -269,14 +267,15 @@ class UsersController extends Controller
|
|||
$user->city = $request->input('city', null);
|
||||
$user->state = $request->input('state', null);
|
||||
$user->country = $request->input('country', null);
|
||||
$user->activated = $request->input('activated', 0);
|
||||
// if a user is editing themselves we should always keep activated true
|
||||
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
$user->vip = $request->input('vip', 0);
|
||||
$user->website = $request->input('website', null);
|
||||
$user->start_date = $request->input('start_date', null);
|
||||
$user->end_date = $request->input('end_date', null);
|
||||
$user->autoassign_licenses = $request->input('autoassign_licenses', 1);
|
||||
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
|
@ -671,4 +670,4 @@ class UsersController extends Controller
|
|||
|
||||
return redirect()->back()->with('error', 'User is not activated, is LDAP synced, or does not have an email address ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,16 @@ class Importer extends Component
|
|||
public $field_map; // we need a separate variable for the field-mapping, because the keys in the normal array are too complicated for Livewire to understand
|
||||
public $file_id; // TODO: I can't figure out *why* we need this, but it really seems like we do. I can't seem to pull the id from the activeFile for some reason?
|
||||
|
||||
// Make these variables public - we set the properties in the constructor so we can localize them (versus the old static arrays)
|
||||
public $accessories_fields;
|
||||
public $assets_fields;
|
||||
public $users_fields;
|
||||
public $licenses_fields;
|
||||
public $locations_fields;
|
||||
public $consumables_fields;
|
||||
public $components_fields;
|
||||
public $aliases_fields;
|
||||
|
||||
protected $rules = [
|
||||
'files.*.file_path' => 'required|string',
|
||||
'files.*.created_at' => 'required|string',
|
||||
|
@ -57,132 +67,34 @@ class Importer extends Component
|
|||
return json_encode(array_filter($tmp));
|
||||
}
|
||||
|
||||
// all of these 'statics', alas, may have to change to something else to handle translations?
|
||||
// I'm not sure. Maybe I use them to 'populate' the translations? TBH, I don't know yet.
|
||||
static $general = [
|
||||
'category' => 'Category',
|
||||
'company' => 'Company',
|
||||
'email' => 'Email',
|
||||
'item_name' => 'Item Name',
|
||||
'location' => 'Location',
|
||||
'maintained' => 'Maintained',
|
||||
'manufacturer' => 'Manufacturer',
|
||||
'notes' => 'Notes',
|
||||
'order_number' => 'Order Number',
|
||||
'purchase_cost' => 'Purchase Cost',
|
||||
'purchase_date' => 'Purchase Date',
|
||||
'quantity' => 'Quantity',
|
||||
'requestable' => 'Requestable',
|
||||
'serial' => 'Serial Number',
|
||||
'supplier' => 'Supplier',
|
||||
'username' => 'Username',
|
||||
'department' => 'Department',
|
||||
];
|
||||
|
||||
static $accessories = [
|
||||
'model_number' => 'Model Number',
|
||||
];
|
||||
|
||||
static $assets = [
|
||||
'asset_tag' => 'Asset Tag',
|
||||
'asset_model' => 'Model Name',
|
||||
'byod' => 'BYOD',
|
||||
'checkout_class' => 'Checkout Type',
|
||||
'checkout_location' => 'Checkout Location',
|
||||
'image' => 'Image Filename',
|
||||
'model_number' => 'Model Number',
|
||||
'full_name' => 'Full Name',
|
||||
'status' => 'Status',
|
||||
'warranty_months' => 'Warranty Months',
|
||||
];
|
||||
|
||||
static $consumables = [
|
||||
'item_no' => "Item Number",
|
||||
'model_number' => "Model Number",
|
||||
'min_amt' => "Minimum Quantity",
|
||||
];
|
||||
|
||||
static $licenses = [
|
||||
'asset_tag' => 'Assigned To Asset',
|
||||
'expiration_date' => 'Expiration Date',
|
||||
'full_name' => 'Full Name',
|
||||
'license_email' => 'Licensed To Email',
|
||||
'license_name' => 'Licensed To Name',
|
||||
'purchase_order' => 'Purchase Order',
|
||||
'reassignable' => 'Reassignable',
|
||||
'seats' => 'Seats',
|
||||
];
|
||||
|
||||
static $users = [
|
||||
'employee_num' => 'Employee Number',
|
||||
'first_name' => 'First Name',
|
||||
'jobtitle' => 'Job Title',
|
||||
'last_name' => 'Last Name',
|
||||
'phone_number' => 'Phone Number',
|
||||
'manager_first_name' => 'Manager First Name',
|
||||
'manager_last_name' => 'Manager Last Name',
|
||||
'activated' => 'Activated',
|
||||
'address' => 'Address',
|
||||
'city' => 'City',
|
||||
'state' => 'State',
|
||||
'country' => 'Country',
|
||||
'vip' => 'VIP'
|
||||
];
|
||||
|
||||
//array of "real fieldnames" to a list of aliases for that field
|
||||
static $aliases = [
|
||||
'model_number' =>
|
||||
[
|
||||
'model',
|
||||
'model no',
|
||||
'model no.',
|
||||
'model number',
|
||||
'model num',
|
||||
'model num.'
|
||||
],
|
||||
'warranty_months' =>
|
||||
[
|
||||
'Warranty',
|
||||
'Warranty Months'
|
||||
],
|
||||
'qty' =>
|
||||
[
|
||||
'QTY',
|
||||
'Quantity'
|
||||
],
|
||||
'min_amt' =>
|
||||
[
|
||||
'Min Amount',
|
||||
'Min QTY'
|
||||
],
|
||||
'next_audit_date' =>
|
||||
[
|
||||
'Next Audit',
|
||||
],
|
||||
|
||||
|
||||
];
|
||||
|
||||
private function getColumns($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'asset':
|
||||
$results = self::$general + self::$assets;
|
||||
$results = $this->assets_fields;
|
||||
break;
|
||||
case 'accessory':
|
||||
$results = self::$general + self::$accessories;
|
||||
$results = $this->accessories_fields;
|
||||
break;
|
||||
case 'consumable':
|
||||
$results = self::$general + self::$consumables;
|
||||
$results = $this->consumables_fields;
|
||||
break;
|
||||
case 'component':
|
||||
$results = $this->components_fields;
|
||||
break;
|
||||
case 'license':
|
||||
$results = self::$general + self::$licenses;
|
||||
$results = $this->licenses_fields;
|
||||
break;
|
||||
case 'user':
|
||||
$results = self::$general + self::$users;
|
||||
$results = $this->users_fields;
|
||||
break;
|
||||
case 'location':
|
||||
$results = $this->locations_fields;
|
||||
break;
|
||||
default:
|
||||
$results = self::$general;
|
||||
$results = [];
|
||||
}
|
||||
asort($results, SORT_FLAG_CASE | SORT_STRING);
|
||||
if ($type == "asset") {
|
||||
|
@ -211,7 +123,7 @@ class Importer extends Component
|
|||
continue;
|
||||
} else {
|
||||
//no, this key is *INVALID* for this import type. Better set it to null
|
||||
// and we'll hope that the aliases or something else picks it up.
|
||||
// and we'll hope that the $aliases_fields or something else picks it up.
|
||||
$this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh.
|
||||
} // TODO - strictly speaking, this isn't necessary here I don't think.
|
||||
}
|
||||
|
@ -222,8 +134,8 @@ class Importer extends Component
|
|||
continue 2; //don't bother with the alias check, go to the next header
|
||||
}
|
||||
}
|
||||
// if you got here, we didn't find a match. Try the aliases
|
||||
foreach (self::$aliases as $key => $alias_values) {
|
||||
// if you got here, we didn't find a match. Try the $aliases_fields
|
||||
foreach ($this->aliases_fields as $key => $alias_values) {
|
||||
foreach ($alias_values as $alias_value) {
|
||||
if (strcasecmp($alias_value, $header) === 0) { // aLsO CaSe-INSENSitiVE!
|
||||
// Make *absolutely* sure that this key actually _exists_ in this import type -
|
||||
|
@ -252,7 +164,6 @@ class Importer extends Component
|
|||
$this->authorize('import');
|
||||
$this->progress = -1; // '-1' means 'don't show the progressbar'
|
||||
$this->progress_bar_class = 'progress-bar-warning';
|
||||
\Log::debug("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk
|
||||
$this->importTypes = [
|
||||
'asset' => trans('general.assets'),
|
||||
'accessory' => trans('general.accessories'),
|
||||
|
@ -260,6 +171,303 @@ class Importer extends Component
|
|||
'component' => trans('general.components'),
|
||||
'license' => trans('general.licenses'),
|
||||
'user' => trans('general.users'),
|
||||
'location' => trans('general.locations'),
|
||||
];
|
||||
|
||||
/**
|
||||
* These are the item-type specific columns
|
||||
*/
|
||||
$this->accessories_fields = [
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'quantity' => trans('general.qty'),
|
||||
'item_name' => trans('general.item_name_var', ['item' => trans('general.accessory')]),
|
||||
'model_number' => trans('general.model_no'),
|
||||
'notes' => trans('general.notes'),
|
||||
'category' => trans('general.category'),
|
||||
'supplier' => trans('general.supplier'),
|
||||
'min_amt' => trans('mail.min_QTY'),
|
||||
'purchase_cost' => trans('general.purchase_cost'),
|
||||
'purchase_date' => trans('general.purchase_date'),
|
||||
'manufacturer' => trans('general.manufacturer'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
];
|
||||
|
||||
$this->assets_fields = [
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'item_name' => trans('general.item_name_var', ['item' => trans('general.asset')]),
|
||||
'asset_tag' => trans('general.asset_tag'),
|
||||
'asset_model' => trans('general.model_name'),
|
||||
'byod' => trans('general.byod'),
|
||||
'model_number' => trans('general.model_no'),
|
||||
'status' => trans('general.status'),
|
||||
'warranty_months' => trans('admin/hardware/form.warranty'),
|
||||
'category' => trans('general.category'),
|
||||
'requestable' => trans('admin/hardware/general.requestable'),
|
||||
'serial' => trans('general.serial_number'),
|
||||
'supplier' => trans('general.supplier'),
|
||||
'purchase_cost' => trans('general.purchase_cost'),
|
||||
'purchase_date' => trans('general.purchase_date'),
|
||||
'purchase_order' => trans('admin/licenses/form.purchase_order'),
|
||||
'asset_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/general.asset')]),
|
||||
'model_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
|
||||
'manufacturer' => trans('general.manufacturer'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
'notes' => trans('general.notes'),
|
||||
'image' => trans('general.importer.image_filename'),
|
||||
/**
|
||||
* Checkout fields:
|
||||
* Assets can be checked out to other assets, people, or locations, but we currently
|
||||
* only support checkout to people and locations in the importer
|
||||
**/
|
||||
'checkout_class' => trans('general.importer.checkout_type'),
|
||||
'first_name' => trans('general.importer.checked_out_to_first_name'),
|
||||
'last_name' => trans('general.importer.checked_out_to_last_name'),
|
||||
'full_name' => trans('general.importer.checked_out_to_fullname'),
|
||||
'email' => trans('general.importer.checked_out_to_email'),
|
||||
'username' => trans('general.importer.checked_out_to_username'),
|
||||
'checkout_location' => trans('general.importer.checkout_location'),
|
||||
];
|
||||
|
||||
$this->consumables_fields = [
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'quantity' => trans('general.qty'),
|
||||
'item_name' => trans('general.item_name_var', ['item' => trans('general.consumable')]),
|
||||
'model_number' => trans('general.model_no'),
|
||||
'notes' => trans('general.notes'),
|
||||
'min_amt' => trans('mail.min_QTY'),
|
||||
'category' => trans('general.category'),
|
||||
'purchase_cost' => trans('general.purchase_cost'),
|
||||
'purchase_date' => trans('general.purchase_date'),
|
||||
'checkout_class' => trans('general.importer.checkout_type'),
|
||||
'supplier' => trans('general.supplier'),
|
||||
'manufacturer' => trans('general.manufacturer'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
'item_no' => trans('admin/consumables/general.item_no'),
|
||||
];
|
||||
|
||||
$this->components_fields = [
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'quantity' => trans('general.qty'),
|
||||
'item_name' => trans('general.item_name_var', ['item' => trans('general.component')]),
|
||||
'model_number' => trans('general.model_no'),
|
||||
'notes' => trans('general.notes'),
|
||||
'category' => trans('general.category'),
|
||||
'supplier' => trans('general.supplier'),
|
||||
'min_amt' => trans('mail.min_QTY'),
|
||||
'purchase_cost' => trans('general.purchase_cost'),
|
||||
'purchase_date' => trans('general.purchase_date'),
|
||||
'manufacturer' => trans('general.manufacturer'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
'serial' => trans('general.serial_number'),
|
||||
];
|
||||
|
||||
$this->licenses_fields = [
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'item_name' => trans('general.item_name_var', ['item' => trans('general.license')]),
|
||||
'asset_tag' => trans('general.importer.checked_out_to_tag'),
|
||||
'expiration_date' => trans('admin/licenses/form.expiration'),
|
||||
'full_name' => trans('general.importer.checked_out_to_fullname'),
|
||||
'license_email' => trans('admin/licenses/form.to_email'),
|
||||
'license_name' => trans('admin/licenses/form.to_name'),
|
||||
'purchase_order' => trans('admin/licenses/form.purchase_order'),
|
||||
'reassignable' => trans('admin/licenses/form.reassignable'),
|
||||
'seats' => trans('admin/licenses/form.seats'),
|
||||
'notes' => trans('general.notes'),
|
||||
'category' => trans('general.category'),
|
||||
'supplier' => trans('general.supplier'),
|
||||
'purchase_cost' => trans('general.purchase_cost'),
|
||||
'purchase_date' => trans('general.purchase_date'),
|
||||
'maintained' => trans('admin/licenses/form.maintained'),
|
||||
'checkout_class' => trans('general.importer.checkout_type'),
|
||||
'serial' => trans('general.license_serial'),
|
||||
];
|
||||
|
||||
$this->users_fields = [
|
||||
'id' => trans('general.id'),
|
||||
'company' => trans('general.company'),
|
||||
'location' => trans('general.location'),
|
||||
'department' => trans('general.department'),
|
||||
'first_name' => trans('general.first_name'),
|
||||
'last_name' => trans('general.last_name'),
|
||||
'notes' => trans('general.notes'),
|
||||
'username' => trans('admin/users/table.username'),
|
||||
'jobtitle' => trans('admin/users/table.title'),
|
||||
'phone_number' => trans('admin/users/table.phone'),
|
||||
'manager_first_name' => trans('general.importer.manager_first_name'),
|
||||
'manager_last_name' => trans('general.importer.manager_last_name'),
|
||||
'activated' => trans('general.activated'),
|
||||
'address' => trans('general.address'),
|
||||
'city' => trans('general.city'),
|
||||
'state' => trans('general.state'),
|
||||
'country' => trans('general.country'),
|
||||
'zip' => trans('general.zip'),
|
||||
'vip' => trans('general.importer.vip'),
|
||||
'remote' => trans('admin/users/general.remote'),
|
||||
'email' => trans('admin/users/table.email'),
|
||||
'website' => trans('general.website'),
|
||||
'avatar' => trans('general.image'),
|
||||
'gravatar' => trans('general.importer.gravatar'),
|
||||
'start_date' => trans('general.start_date'),
|
||||
'end_date' => trans('general.end_date'),
|
||||
'employee_number' => trans('general.employee_number'),
|
||||
];
|
||||
|
||||
$this->locations_fields = [
|
||||
'name' => trans('general.item_name_var', ['item' => trans('general.location')]),
|
||||
'address' => trans('general.address'),
|
||||
'address2' => trans('general.importer.address2'),
|
||||
'city' => trans('general.city'),
|
||||
'state' => trans('general.state'),
|
||||
'country' => trans('general.country'),
|
||||
'zip' => trans('general.zip'),
|
||||
'currency' => trans('general.importer.currency'),
|
||||
'ldap_ou' => trans('admin/locations/table.ldap_ou'),
|
||||
'manager_username' => trans('general.importer.manager_username'),
|
||||
'manager' => trans('general.importer.manager_full_name'),
|
||||
'parent_location' => trans('admin/locations/table.parent'),
|
||||
];
|
||||
|
||||
// "real fieldnames" to a list of aliases for that field
|
||||
$this->aliases_fields = [
|
||||
'item_name' =>
|
||||
[
|
||||
'item name',
|
||||
'asset name',
|
||||
'accessory name',
|
||||
'user name',
|
||||
'consumable name',
|
||||
'component name',
|
||||
'name',
|
||||
],
|
||||
'item_no' => [
|
||||
'item number',
|
||||
'item no.',
|
||||
'item #',
|
||||
],
|
||||
'asset_model' =>
|
||||
[
|
||||
'model name',
|
||||
'model',
|
||||
],
|
||||
'gravatar' =>
|
||||
[
|
||||
'gravatar',
|
||||
],
|
||||
'currency' =>
|
||||
[
|
||||
'$',
|
||||
],
|
||||
'jobtitle' =>
|
||||
[
|
||||
'job title for user',
|
||||
'job title',
|
||||
],
|
||||
'username' =>
|
||||
[
|
||||
'user name',
|
||||
'username',
|
||||
trans('general.importer.checked_out_to_username'),
|
||||
],
|
||||
'first_name' =>
|
||||
[
|
||||
'first name',
|
||||
trans('general.importer.checked_out_to_first_name'),
|
||||
],
|
||||
'last_name' =>
|
||||
[
|
||||
'last name',
|
||||
'lastname',
|
||||
trans('general.importer.checked_out_to_last_name'),
|
||||
],
|
||||
'email' =>
|
||||
[
|
||||
'email',
|
||||
'e-mail',
|
||||
trans('general.importer.checked_out_to_email'),
|
||||
],
|
||||
'phone_number' =>
|
||||
[
|
||||
'phone',
|
||||
'phone number',
|
||||
'phone num',
|
||||
'telephone number',
|
||||
'telephone',
|
||||
'tel.',
|
||||
],
|
||||
'serial' =>
|
||||
[
|
||||
'serial number',
|
||||
'serial no.',
|
||||
'serial no',
|
||||
'product key',
|
||||
'key',
|
||||
],
|
||||
'model_number' =>
|
||||
[
|
||||
'model',
|
||||
'model no',
|
||||
'model no.',
|
||||
'model number',
|
||||
'model num',
|
||||
'model num.'
|
||||
],
|
||||
'warranty_months' =>
|
||||
[
|
||||
'Warranty',
|
||||
'Warranty Months'
|
||||
],
|
||||
'qty' =>
|
||||
[
|
||||
'QTY',
|
||||
'Quantity'
|
||||
],
|
||||
'zip' =>
|
||||
[
|
||||
'Postal Code',
|
||||
'Post Code',
|
||||
'Zip Code'
|
||||
],
|
||||
'min_amt' =>
|
||||
[
|
||||
'Min Amount',
|
||||
'Minimum Amount',
|
||||
'Min Quantity',
|
||||
'Minimum Quantity',
|
||||
],
|
||||
'next_audit_date' =>
|
||||
[
|
||||
'Next Audit',
|
||||
],
|
||||
'address2' =>
|
||||
[
|
||||
'Address 2',
|
||||
'Address2',
|
||||
],
|
||||
'ldap_ou' =>
|
||||
[
|
||||
'LDAP OU',
|
||||
'OU',
|
||||
],
|
||||
'parent_location' =>
|
||||
[
|
||||
'Parent',
|
||||
'Parent Location',
|
||||
],
|
||||
'manager' =>
|
||||
[
|
||||
'Managed By',
|
||||
'Manager Name',
|
||||
'Manager Full Name',
|
||||
],
|
||||
'manager_username' =>
|
||||
[
|
||||
'Manager Username',
|
||||
],
|
||||
];
|
||||
|
||||
$this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean
|
||||
|
@ -273,8 +481,7 @@ class Importer extends Component
|
|||
|
||||
public function selectFile($id)
|
||||
{
|
||||
\Log::debug("TOGGLE EVENT FIRED!");
|
||||
\Log::debug("The ID we are trying to find is AS FOLLOWS: ".$id);
|
||||
|
||||
$this->activeFile = Import::find($id);
|
||||
$this->field_map = null;
|
||||
foreach($this->activeFile->header_row as $element) {
|
||||
|
@ -284,11 +491,9 @@ class Importer extends Component
|
|||
$this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings
|
||||
}
|
||||
}
|
||||
//$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; // this is wrong
|
||||
$this->file_id = $id;
|
||||
$this->import_errors = null;
|
||||
$this->statusText = null;
|
||||
\Log::debug("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ class CheckForSetup
|
|||
|
||||
if (Setting::setupCompleted()) {
|
||||
if ($request->is('setup*')) {
|
||||
return redirect(url('/'));
|
||||
return redirect(config('app.url'));
|
||||
} else {
|
||||
return $next($request);
|
||||
}
|
||||
} else {
|
||||
if (! ($request->is('setup*')) && ! ($request->is('.env')) && ! ($request->is('health'))) {
|
||||
return redirect(url('/').'/setup');
|
||||
return redirect(config('app.url').'/setup');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
|
|
@ -26,6 +26,8 @@ class CustomFieldRequest extends FormRequest
|
|||
{
|
||||
$rules = [];
|
||||
|
||||
$rules['associate_fieldsets.*'] = 'nullable|integer|exists:custom_fieldsets,id';
|
||||
|
||||
switch ($this->method()) {
|
||||
|
||||
// Brand new
|
||||
|
@ -54,4 +56,11 @@ class CustomFieldRequest extends FormRequest
|
|||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'associate_fieldsets.*.exists' => trans('admin/custom_fields/message/does_not_exist'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ class AssetMaintenancesTransformer
|
|||
'user_id' => ($assetmaintenance->admin) ? ['id' => $assetmaintenance->admin->id, 'name'=> e($assetmaintenance->admin->getFullNameAttribute())] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($assetmaintenance->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($assetmaintenance->updated_at, 'datetime'),
|
||||
'is_warranty'=> $assetmaintenance->is_warranty,
|
||||
|
||||
];
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ class CategoriesTransformer
|
|||
case 'component':
|
||||
$category->item_count = $category->components_count;
|
||||
break;
|
||||
case 'license':
|
||||
$category->item_count = $category->licenses_count;
|
||||
break;
|
||||
default:
|
||||
$category->item_count = 0;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class ComponentsTransformer
|
|||
'id' => (int) $component->category->id,
|
||||
'name' => e($component->category->name),
|
||||
] : null,
|
||||
'supplier' => ($component->supplier) ? ['id' => $component->supplier->id, 'name'=> e($component->supplier->name)] : null,
|
||||
'order_number' => e($component->order_number),
|
||||
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost),
|
||||
|
|
|
@ -31,6 +31,7 @@ class ConsumablesTransformer
|
|||
'item_no' => e($consumable->item_no),
|
||||
'location' => ($consumable->location) ? ['id' => (int) $consumable->location->id, 'name' => e($consumable->location->name)] : null,
|
||||
'manufacturer' => ($consumable->manufacturer) ? ['id' => (int) $consumable->manufacturer->id, 'name' => e($consumable->manufacturer->name)] : null,
|
||||
'supplier' => ($consumable->supplier) ? ['id' => $consumable->supplier->id, 'name'=> e($consumable->supplier->name)] : null,
|
||||
'min_amt' => (int) $consumable->min_amt,
|
||||
'model_number' => ($consumable->model_number != '') ? e($consumable->model_number) : null,
|
||||
'remaining' => $consumable->numRemaining(),
|
||||
|
|
|
@ -48,6 +48,7 @@ class CustomFieldsTransformer
|
|||
'type' => e($field->element),
|
||||
'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false,
|
||||
'display_in_user_view' => ($field->display_in_user_view =='1') ? true : false,
|
||||
'auto_add_to_fieldsets' => ($field->auto_add_to_fieldsets == '1') ? true : false,
|
||||
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
|
||||
];
|
||||
|
|
|
@ -56,7 +56,7 @@ class LicensesTransformer
|
|||
'checkin' => Gate::allows('checkin', License::class),
|
||||
'clone' => Gate::allows('create', License::class),
|
||||
'update' => Gate::allows('update', License::class),
|
||||
'delete' => Gate::allows('delete', License::class),
|
||||
'delete' => (Gate::allows('delete', License::class) && ($license->seats == $license->availCount()->count())) ? true : false,
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
|
|
|
@ -29,6 +29,7 @@ class ManufacturersTransformer
|
|||
'url' => e($manufacturer->url),
|
||||
'image' => ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.e($manufacturer->image)) : null,
|
||||
'support_url' => e($manufacturer->support_url),
|
||||
'warranty_lookup_url' => e($manufacturer->warranty_lookup_url),
|
||||
'support_phone' => e($manufacturer->support_phone),
|
||||
'support_email' => e($manufacturer->support_email),
|
||||
'assets_count' => (int) $manufacturer->assets_count,
|
||||
|
|
|
@ -41,6 +41,8 @@ class SuppliersTransformer
|
|||
'assets_count' => (int) $supplier->assets_count,
|
||||
'accessories_count' => (int) $supplier->accessories_count,
|
||||
'licenses_count' => (int) $supplier->licenses_count,
|
||||
'consumables_count' => (int) $supplier->consumables_count,
|
||||
'components_count' => (int) $supplier->components_count,
|
||||
'notes' => ($supplier->notes) ? e($supplier->notes) : null,
|
||||
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'),
|
||||
|
|
|
@ -56,6 +56,7 @@ class UsersTransformer
|
|||
'notes'=> e($user->notes),
|
||||
'permissions' => $user->decodePermissions(),
|
||||
'activated' => ($user->activated == '1') ? true : false,
|
||||
'autoassign_licenses' => ($user->autoassign_licenses == '1') ? true : false,
|
||||
'ldap_import' => ($user->ldap_import == '1') ? true : false,
|
||||
'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false,
|
||||
'two_factor_optin' => ($user->two_factor_active()) ? true : false,
|
||||
|
|
|
@ -12,7 +12,10 @@ class AssetImporter extends ItemImporter
|
|||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
$this->defaultStatusLabelId = Statuslabel::first()->id;
|
||||
|
||||
if (!is_null(Statuslabel::first())) {
|
||||
$this->defaultStatusLabelId = Statuslabel::first()->id;
|
||||
}
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
|
@ -60,7 +63,7 @@ class AssetImporter extends ItemImporter
|
|||
$asset_tag = Asset::autoincrement_asset();
|
||||
}
|
||||
|
||||
$asset = Asset::where(['asset_tag'=> $asset_tag])->first();
|
||||
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
||||
if ($asset) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Asset '.$asset_tag.' already exists');
|
||||
|
@ -114,6 +117,11 @@ class AssetImporter extends ItemImporter
|
|||
$item['next_audit_date'] = $this->item['next_audit_date'];
|
||||
}
|
||||
|
||||
$item['asset_eol_date'] = null;
|
||||
if (isset($this->item['asset_eol_date'])) {
|
||||
$item['asset_eol_date'] = $this->item['asset_eol_date'];
|
||||
}
|
||||
|
||||
if ($editingAsset) {
|
||||
$asset->update($item);
|
||||
} else {
|
||||
|
@ -127,10 +135,9 @@ class AssetImporter extends ItemImporter
|
|||
}
|
||||
}
|
||||
|
||||
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
|
||||
// $asset->unsetEventDispatcher();
|
||||
|
||||
if ($asset->save()) {
|
||||
$asset->logCreate('Imported using csv importer');
|
||||
$asset->logCreate(trans('general.importer.import_note'));
|
||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
// If we have a target to checkout to, lets do so.
|
||||
|
|
|
@ -27,57 +27,14 @@ abstract class Importer
|
|||
protected $updating;
|
||||
/**
|
||||
* Default Map of item fields->csv names
|
||||
*
|
||||
* This has been moved into Livewire/Importer.php to be more granular.
|
||||
* @todo - remove references to this property since we don't use it anymore.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultFieldMap = [
|
||||
'asset_tag' => 'asset tag',
|
||||
'activated' => 'activated',
|
||||
'category' => 'category',
|
||||
'checkout_class' => 'checkout type', // Supports Location or User for assets. Using checkout_class instead of checkout_type because type exists on asset already.
|
||||
'checkout_location' => 'checkout location',
|
||||
'company' => 'company',
|
||||
'item_name' => 'item name',
|
||||
'item_number' => 'item number',
|
||||
'image' => 'image',
|
||||
'expiration_date' => 'expiration date',
|
||||
'location' => 'location',
|
||||
'notes' => 'notes',
|
||||
'license_email' => 'licensed to email',
|
||||
'license_name' => 'licensed to name',
|
||||
'maintained' => 'maintained',
|
||||
'manufacturer' => 'manufacturer',
|
||||
'asset_model' => 'model name',
|
||||
'model_number' => 'model number',
|
||||
'order_number' => 'order number',
|
||||
'purchase_cost' => 'purchase cost',
|
||||
'purchase_date' => 'purchase date',
|
||||
'purchase_order' => 'purchase order',
|
||||
'qty' => 'quantity',
|
||||
'reassignable' => 'reassignable',
|
||||
'requestable' => 'requestable',
|
||||
'seats' => 'seats',
|
||||
'serial' => 'serial number',
|
||||
'status' => 'status',
|
||||
'supplier' => 'supplier',
|
||||
'termination_date' => 'termination date',
|
||||
'warranty_months' => 'warranty',
|
||||
'full_name' => 'full name',
|
||||
'email' => 'email',
|
||||
'username' => 'username',
|
||||
'address' => 'address',
|
||||
'city' => 'city',
|
||||
'state' => 'state',
|
||||
'country' => 'country',
|
||||
'jobtitle' => 'job title',
|
||||
'employee_num' => 'employee number',
|
||||
'phone_number' => 'phone number',
|
||||
'first_name' => 'first name',
|
||||
'last_name' => 'last name',
|
||||
'department' => 'department',
|
||||
'manager_first_name' => 'manager first name',
|
||||
'manager_last_name' => 'manager last name',
|
||||
'min_amt' => 'minimum quantity',
|
||||
'remote' => 'remote',
|
||||
|
||||
];
|
||||
/**
|
||||
* Map of item fields->csv names
|
||||
|
@ -119,7 +76,7 @@ abstract class Importer
|
|||
} else {
|
||||
$this->csv = Reader::createFromString($file);
|
||||
}
|
||||
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
|
||||
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
}
|
||||
|
||||
// Cached Values for import lookups
|
||||
|
@ -198,11 +155,11 @@ abstract class Importer
|
|||
$val = $default;
|
||||
$key = $this->lookupCustomKey($key);
|
||||
|
||||
$this->log("Custom Key: ${key}");
|
||||
// $this->log("Custom Key: ${key}");
|
||||
if (array_key_exists($key, $array)) {
|
||||
$val = Encoding::toUTF8(trim($array[$key]));
|
||||
}
|
||||
$this->log("${key}: ${val}");
|
||||
//$this->log("${key}: ${val}");
|
||||
return $val;
|
||||
}
|
||||
|
||||
|
@ -280,10 +237,13 @@ abstract class Importer
|
|||
* @return User Model w/ matching name
|
||||
* @internal param array $user_array User details parsed from csv
|
||||
*/
|
||||
protected function createOrFetchUser($row)
|
||||
protected function createOrFetchUser($row, $type = 'user')
|
||||
{
|
||||
|
||||
$user_array = [
|
||||
'full_name' => $this->findCsvMatch($row, 'full_name'),
|
||||
'first_name' => $this->findCsvMatch($row, 'first_name'),
|
||||
'last_name' => $this->findCsvMatch($row, 'last_name'),
|
||||
'email' => $this->findCsvMatch($row, 'email'),
|
||||
'manager_id'=> '',
|
||||
'department_id' => '',
|
||||
|
@ -292,48 +252,53 @@ abstract class Importer
|
|||
'remote' => $this->fetchHumanBoolean(($this->findCsvMatch($row, 'remote'))),
|
||||
];
|
||||
|
||||
// Maybe we're lucky and the user already exists.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
|
||||
return $user;
|
||||
if ($type == 'manager') {
|
||||
$user_array['full_name'] = $this->findCsvMatch($row, 'manager');
|
||||
$user_array['username'] = $this->findCsvMatch($row, 'manager_username');
|
||||
}
|
||||
|
||||
// If the full name is empty, bail out--we need this to extract first name (at the very least)
|
||||
if (empty($user_array['full_name'])) {
|
||||
$this->log('Insufficient user data provided (Full name is required)- skipping user creation, just adding asset');
|
||||
// Maybe we're lucky and the username was passed and it already exists.
|
||||
if (!empty($user_array['username'])) {
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the full name and username is empty, bail out--we need this to extract first name (at the very least)
|
||||
if ((empty($user_array['username'])) && (empty($user_array['full_name'])) && (empty($user_array['first_name']))) {
|
||||
$this->log('Insufficient user data provided (Full name, first name or username is required) - skipping user creation.');
|
||||
\Log::debug('User array: ');
|
||||
\Log::debug(print_r($user_array, true));
|
||||
\Log::debug(print_r($row, true));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the user actually an ID?
|
||||
if ($user = $this->findUserByNumber($user_array['full_name'])) {
|
||||
return $user;
|
||||
}
|
||||
$this->log('User does not appear to be an id with number: '.$user_array['full_name'].'. Continuing through our processes');
|
||||
|
||||
// Populate email if it does not exist.
|
||||
if (empty($user_array['email'])) {
|
||||
$user_array['email'] = User::generateEmailFromFullName($user_array['full_name']);
|
||||
}
|
||||
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format);
|
||||
$user_array['first_name'] = $user_formatted_array['first_name'];
|
||||
$user_array['last_name'] = $user_formatted_array['last_name'];
|
||||
if (empty($user_array['first_name'])) {
|
||||
// Get some fields for first name and last name based off of full name
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format);
|
||||
$user_array['first_name'] = $user_formatted_array['first_name'];
|
||||
$user_array['last_name'] = $user_formatted_array['last_name'];
|
||||
}
|
||||
|
||||
if (empty($user_array['username'])) {
|
||||
$user_array['username'] = $user_formatted_array['username'];
|
||||
if ($this->usernameFormat == 'email') {
|
||||
$user_array['username'] = $user_array['email'];
|
||||
}
|
||||
}
|
||||
|
||||
// Does this ever actually fire??
|
||||
// Check for a matching user after trying to guess username.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
|
||||
return $user;
|
||||
// Check for a matching username one more time after trying to guess username.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
// If at this point we have not found a username or first name, bail out in shame.
|
||||
|
@ -341,7 +306,7 @@ abstract class Importer
|
|||
return false;
|
||||
}
|
||||
|
||||
// No Luck, let's create one.
|
||||
// No luck finding a user on username or first name, let's create one.
|
||||
$user = new User;
|
||||
$user->first_name = $user_array['first_name'];
|
||||
$user->last_name = $user_array['last_name'];
|
||||
|
@ -356,9 +321,9 @@ abstract class Importer
|
|||
|
||||
if ($user->save()) {
|
||||
$this->log('User '.$user_array['username'].' created');
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
$this->logError($user, 'User "'.$user_array['username'].'" was not able to be created.');
|
||||
|
||||
return false;
|
||||
|
|
|
@ -60,8 +60,8 @@ class ItemImporter extends Importer
|
|||
$this->item['department_id'] = $this->createOrFetchDepartment($item_department);
|
||||
}
|
||||
|
||||
$item_manager_first_name = $this->findCsvMatch($row, 'manage_first_name');
|
||||
$item_manager_last_name = $this->findCsvMatch($row, 'manage_last_name');
|
||||
$item_manager_first_name = $this->findCsvMatch($row, 'manager_first_name');
|
||||
$item_manager_last_name = $this->findCsvMatch($row, 'manager_last_name');
|
||||
|
||||
if ($this->shouldUpdateField($item_manager_first_name)) {
|
||||
$this->item['manager_id'] = $this->fetchManager($item_manager_first_name, $item_manager_last_name);
|
||||
|
@ -87,6 +87,11 @@ class ItemImporter extends Importer
|
|||
$this->item['next_audit_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'next_audit_date')));
|
||||
}
|
||||
|
||||
$this->item['asset_eol_date'] = null;
|
||||
if ($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$this->item['asset_eol_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'asset_eol_date')));
|
||||
}
|
||||
|
||||
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
|
||||
$this->item['requestable'] = $this->findCsvMatch($row, 'requestable');
|
||||
$this->item['user_id'] = $this->user_id;
|
||||
|
@ -103,13 +108,13 @@ class ItemImporter extends Importer
|
|||
/**
|
||||
* Parse row to determine what (if anything) we should checkout to.
|
||||
* @param array $row CSV Row being parsed
|
||||
* @return SnipeModel Model to be checked out to
|
||||
* @return ?SnipeModel Model to be checked out to
|
||||
*/
|
||||
protected function determineCheckout($row)
|
||||
{
|
||||
// We only support checkout-to-location for asset, so short circuit otherwise.
|
||||
if (get_class($this) != AssetImporter::class) {
|
||||
return $this->createOrFetchUser($row);
|
||||
// Locations don't get checked out to anyone/anything
|
||||
if (get_class($this) == LocationImporter::class) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strtolower($this->item['checkout_class']) === 'location' && $this->findCsvMatch($row, 'checkout_location') != null ) {
|
||||
|
|
102
app/Importer/LocationImporter.php
Normal file
102
app/Importer/LocationImporter.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Location;
|
||||
|
||||
/**
|
||||
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
|
||||
* Importer\Importer.php. [ALG]
|
||||
*
|
||||
* Class LocationImporter
|
||||
*/
|
||||
class LocationImporter extends ItemImporter
|
||||
{
|
||||
protected $locations;
|
||||
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row);
|
||||
$this->createLocationIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a location if a duplicate does not exist.
|
||||
* @todo Investigate how this should interact with Importer::createLocationIfNotExists
|
||||
*
|
||||
* @author A. Gianotto
|
||||
* @since 6.1.0
|
||||
* @param array $row
|
||||
*/
|
||||
public function createLocationIfNotExists(array $row)
|
||||
{
|
||||
|
||||
$editingLocation = false;
|
||||
$location = Location::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
|
||||
if ($location) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Location '.$this->item['name'].' already exists');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating Location');
|
||||
$editingLocation = true;
|
||||
} else {
|
||||
$this->log('No Matching Location, Create a new one');
|
||||
$location = new Location;
|
||||
}
|
||||
|
||||
// Pull the records from the CSV to determine their values
|
||||
$this->item['name'] = $this->findCsvMatch($row, 'name');
|
||||
$this->item['address'] = $this->findCsvMatch($row, 'address');
|
||||
$this->item['address2'] = $this->findCsvMatch($row, 'address2');
|
||||
$this->item['city'] = $this->findCsvMatch($row, 'city');
|
||||
$this->item['state'] = $this->findCsvMatch($row, 'state');
|
||||
$this->item['country'] = $this->findCsvMatch($row, 'country');
|
||||
$this->item['zip'] = $this->findCsvMatch($row, 'zip');
|
||||
$this->item['currency'] = $this->findCsvMatch($row, 'currency');
|
||||
$this->item['ldap_ou'] = $this->findCsvMatch($row, 'ldap_ou');
|
||||
$this->item['manager'] = $this->findCsvMatch($row, 'manager');
|
||||
$this->item['manager_username'] = $this->findCsvMatch($row, 'manager_username');
|
||||
$this->item['user_id'] = \Auth::user()->id;
|
||||
|
||||
if ($this->findCsvMatch($row, 'parent_location')) {
|
||||
$this->item['parent_id'] = $this->createOrFetchLocation($this->findCsvMatch($row, 'parent_location'));
|
||||
}
|
||||
|
||||
if (!empty($this->item['manager'])) {
|
||||
if ($manager = $this->createOrFetchUser($row, 'manager')) {
|
||||
$this->item['manager_id'] = $manager->id;
|
||||
}
|
||||
}
|
||||
|
||||
\Log::debug('Item array is: ');
|
||||
\Log::debug(print_r($this->item, true));
|
||||
|
||||
|
||||
if ($editingLocation) {
|
||||
\Log::debug('Updating existing location');
|
||||
$location->update($this->sanitizeItemForUpdating($location));
|
||||
} else {
|
||||
\Log::debug('Creating location');
|
||||
$location->fill($this->sanitizeItemForStoring($location));
|
||||
}
|
||||
|
||||
if ($location->save()) {
|
||||
$this->log('Location '.$location->name.' created or updated from CSV import');
|
||||
return $location;
|
||||
|
||||
} else {
|
||||
\Log::debug($location->getErrors());
|
||||
return $location->errors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -42,23 +42,29 @@ class UserImporter extends ItemImporter
|
|||
public function createUserIfNotExists(array $row)
|
||||
{
|
||||
// Pull the records from the CSV to determine their values
|
||||
$this->item['id'] = $this->findCsvMatch($row, 'id');
|
||||
$this->item['username'] = $this->findCsvMatch($row, 'username');
|
||||
$this->item['first_name'] = $this->findCsvMatch($row, 'first_name');
|
||||
$this->item['last_name'] = $this->findCsvMatch($row, 'last_name');
|
||||
$this->item['email'] = $this->findCsvMatch($row, 'email');
|
||||
$this->item['gravatar'] = $this->findCsvMatch($row, 'gravatar');
|
||||
$this->item['phone'] = $this->findCsvMatch($row, 'phone_number');
|
||||
$this->item['website'] = $this->findCsvMatch($row, 'website');
|
||||
$this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle');
|
||||
$this->item['address'] = $this->findCsvMatch($row, 'address');
|
||||
$this->item['city'] = $this->findCsvMatch($row, 'city');
|
||||
$this->item['state'] = $this->findCsvMatch($row, 'state');
|
||||
$this->item['country'] = $this->findCsvMatch($row, 'country');
|
||||
$this->item['start_date'] = $this->findCsvMatch($row, 'start_date');
|
||||
$this->item['end_date'] = $this->findCsvMatch($row, 'end_date');
|
||||
$this->item['zip'] = $this->findCsvMatch($row, 'zip');
|
||||
$this->item['activated'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')) == 1) ? '1' : 0;
|
||||
$this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num');
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
|
||||
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
|
||||
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
|
||||
$this->item['vip'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
|
||||
$this->item['vip'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
|
||||
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'autoassign_licenses')) ==1 ) ? '1' : 0;
|
||||
|
||||
|
||||
$user_department = $this->findCsvMatch($row, 'department');
|
||||
|
@ -71,13 +77,18 @@ class UserImporter extends ItemImporter
|
|||
$user_formatted_array = User::generateFormattedNameFromFullName($user_full_name, Setting::getSettings()->username_format);
|
||||
$this->item['username'] = $user_formatted_array['username'];
|
||||
}
|
||||
|
||||
$user = User::where('username', $this->item['username'])->first();
|
||||
if ($user) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching User '.$this->item['name'].' already exists. ');
|
||||
\Log::debug('A matching User '.$this->item['name'].' already exists. ');
|
||||
|
||||
// Check if a numeric ID was passed. If it does, use that above all else.
|
||||
if ((array_key_exists('id', $this->item) && ($this->item['id'] != "") && (is_numeric($this->item['id'])))) {
|
||||
$user = User::find($this->item['id']);
|
||||
} else {
|
||||
$user = User::where('username', $this->item['username'])->first();
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
|
||||
if (! $this->updating) {
|
||||
\Log::debug('A matching User '.$this->item['name'].' already exists. ');
|
||||
return;
|
||||
}
|
||||
$this->log('Updating User');
|
||||
|
@ -104,7 +115,6 @@ class UserImporter extends ItemImporter
|
|||
$user->fill($this->sanitizeItemForStoring($user));
|
||||
|
||||
if ($user->save()) {
|
||||
// $user->logCreate('Imported using CSV Importer');
|
||||
$this->log('User '.$this->item['name'].' was created');
|
||||
|
||||
if (($user->email) && ($user->activated == '1')) {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
| CSV | Item | Applicable Types |
|
||||
|---------------------|------------------|-------------------------------------------|
|
||||
| activated | | User |
|
||||
| asset tag | asset_tag | Asset |
|
||||
| category | category | All |
|
||||
| company | company | All |
|
||||
| department_id | | User ? All |
|
||||
| item name | item_name | All |
|
||||
| image | image | Asset |
|
||||
| email | | |
|
||||
| expiration date | expiration_date | License |
|
||||
| location | location | All |
|
||||
| notes | notes | All |
|
||||
| licensed to email | license_email | License |
|
||||
| licensed to name | license_name | License |
|
||||
| maintained | maintained | License |
|
||||
| manager_id | | User |
|
||||
| manufacturer | manufacturer | All |
|
||||
| model name | asset_model | Asset |
|
||||
| model number | model_number | Asset |
|
||||
| order number | order_number | All ? |
|
||||
| purchase cost | purchase_cost | All ? |
|
||||
| purchase date | purchase_date | All ? |
|
||||
| purchase order | purchase_order | License |
|
||||
| quantity | qty | Accessory, Consumable, Component, License |
|
||||
| reassignable | reassignable | License |
|
||||
| requestable | requestable | Asset, Accessory? |
|
||||
| seats | seats | License |
|
||||
| serial number | serial | Asset, license |
|
||||
| status | status | Asset ? All |
|
||||
| supplier | supplier | Asset ? All |
|
||||
| minimum quantity | min_amt | Consumable |
|
||||
| termination date | termination_date | License |
|
||||
| warranty months | warranty_months | Asset |
|
||||
| User Related Fields | assigned_to | Asset |
|
||||
| name | | |
|
||||
| email | | |
|
||||
| username | | |
|
||||
| address | address | User |
|
||||
| city | city | User |
|
||||
| state | state | User |
|
||||
| country | country | User |
|
||||
| vip | vip | User |
|
||||
| byod | byod | Asset |
|
||||
|
|
@ -2,22 +2,21 @@
|
|||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Recipients\AdminRecipient;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAccessoryNotification;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
use App\Notifications\CheckinLicenseSeatNotification;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Exception;
|
||||
|
@ -25,18 +24,17 @@ use Log;
|
|||
|
||||
class CheckoutableListener
|
||||
{
|
||||
private array $skipNotificationsFor = [
|
||||
Component::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Notify the user about the checked out checkoutable and add a record to the
|
||||
* checkout_requests table.
|
||||
* Notify the user and post to webhook about the checked out checkoutable
|
||||
* and add a record to the checkout_requests table.
|
||||
*/
|
||||
public function onCheckedOut($event)
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if (! $event->checkedOutTo instanceof User) {
|
||||
if ($this->shouldNotSendAnyNotifications($event->checkoutable)){
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -46,6 +44,11 @@ class CheckoutableListener
|
|||
$acceptance = $this->getCheckoutAcceptance($event);
|
||||
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event));
|
||||
}
|
||||
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$this->getNotifiables($event),
|
||||
|
@ -63,16 +66,13 @@ class CheckoutableListener
|
|||
}
|
||||
|
||||
/**
|
||||
* Notify the user about the checked in checkoutable
|
||||
* Notify the user and post to webhook about the checked in checkoutable
|
||||
*/
|
||||
public function onCheckedIn($event)
|
||||
{
|
||||
\Log::debug('onCheckedIn in the Checkoutable listener fired');
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if (! $event->checkedOutTo instanceof User) {
|
||||
if ($this->shouldNotSendAnyNotifications($event->checkoutable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,11 @@ class CheckoutableListener
|
|||
}
|
||||
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckinNotification($event));
|
||||
}
|
||||
|
||||
// Use default locale
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
|
@ -182,11 +187,11 @@ class CheckoutableListener
|
|||
/**
|
||||
* Get the appropriate notification for the event
|
||||
*
|
||||
* @param CheckoutableCheckedIn $event
|
||||
* @param CheckoutAcceptance $acceptance
|
||||
* @param CheckoutableCheckedOut $event
|
||||
* @param CheckoutAcceptance|null $acceptance
|
||||
* @return Notification
|
||||
*/
|
||||
private function getCheckoutNotification($event, $acceptance)
|
||||
private function getCheckoutNotification($event, $acceptance = null)
|
||||
{
|
||||
$notificationClass = null;
|
||||
|
||||
|
@ -225,4 +230,14 @@ class CheckoutableListener
|
|||
'App\Listeners\CheckoutableListener@onCheckedOut'
|
||||
);
|
||||
}
|
||||
|
||||
private function shouldNotSendAnyNotifications($checkoutable): bool
|
||||
{
|
||||
return in_array(get_class($checkoutable), $this->skipNotificationsFor);
|
||||
}
|
||||
|
||||
private function shouldSendWebhookNotification(): bool
|
||||
{
|
||||
return Setting::getSettings() && Setting::getSettings()->webhook_endpoint;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -330,7 +330,11 @@ class Accessory extends SnipeModel
|
|||
|
||||
|
||||
/**
|
||||
* Check how many items of an accessory remain
|
||||
* Check how many items of an accessory remain.
|
||||
*
|
||||
* In order to use this model method, you MUST call withCount('users as users_count')
|
||||
* on the eloquent query in the controller, otherwise $this->>users_count will be null and
|
||||
* bad things happen.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
|
|
|
@ -70,19 +70,6 @@ class Asset extends Depreciable
|
|||
*/
|
||||
protected $injectUniqueIdentifier = true;
|
||||
|
||||
// We set these as protected dates so that they will be easily accessible via Carbon
|
||||
protected $dates = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
'purchase_date',
|
||||
'last_checkout',
|
||||
'expected_checkin',
|
||||
'last_audit_date',
|
||||
'next_audit_date'
|
||||
];
|
||||
|
||||
|
||||
protected $casts = [
|
||||
'purchase_date' => 'date',
|
||||
'last_checkout' => 'datetime',
|
||||
|
@ -96,11 +83,14 @@ class Asset extends Depreciable
|
|||
'rtd_company_id' => 'integer',
|
||||
'supplier_id' => 'integer',
|
||||
'byod' => 'boolean',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'max:255|nullable',
|
||||
'model_id' => 'required|integer|exists:models,id',
|
||||
'model_id' => 'required|integer|exists:models,id,deleted_at,NULL',
|
||||
'status_id' => 'required|integer|exists:status_labels,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'warranty_months' => 'numeric|nullable|digits_between:0,240',
|
||||
|
@ -413,7 +403,7 @@ class Asset extends Depreciable
|
|||
*/
|
||||
public function components()
|
||||
{
|
||||
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty', 'created_at')->withTrashed();
|
||||
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty', 'created_at');
|
||||
}
|
||||
|
||||
|
||||
|
@ -919,7 +909,13 @@ class Asset extends Depreciable
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getComponentCost(){
|
||||
$cost = 0;
|
||||
foreach($this->components as $component) {
|
||||
$cost += $component->pivot->assigned_qty*$component->purchase_cost;
|
||||
}
|
||||
return $cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------
|
||||
|
@ -951,8 +947,10 @@ class Asset extends Depreciable
|
|||
->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%')
|
||||
->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%')
|
||||
->orWhere('assets_users.username', 'LIKE', '%'.$term.'%')
|
||||
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%"]);
|
||||
|
||||
->orWhereMultipleColumns([
|
||||
'assets_users.first_name',
|
||||
'assets_users.last_name',
|
||||
], $term);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1347,7 +1345,10 @@ class Asset extends Depreciable
|
|||
})->orWhere(function ($query) use ($search) {
|
||||
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%"])
|
||||
->orWhereMultipleColumns([
|
||||
'assets_users.first_name',
|
||||
'assets_users.last_name',
|
||||
], $search)
|
||||
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');
|
||||
|
@ -1666,7 +1667,7 @@ class Asset extends Depreciable
|
|||
public function scopeOrderManufacturer($query, $order)
|
||||
{
|
||||
return $query->join('models as order_asset_model', 'assets.model_id', '=', 'order_asset_model.id')
|
||||
->join('manufacturers as manufacturer_order', 'order_asset_model.manufacturer_id', '=', 'manufacturer_order.id')
|
||||
->leftjoin('manufacturers as manufacturer_order', 'order_asset_model.manufacturer_id', '=', 'manufacturer_order.id')
|
||||
->orderBy('manufacturer_order.name', $order);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +95,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
|||
*/
|
||||
public function setCostAttribute($value)
|
||||
{
|
||||
$value = Helper::ParseFloat($value);
|
||||
if ($value == '0.0') {
|
||||
$value = Helper::ParseCurrency($value);
|
||||
if ($value == 0) {
|
||||
$value = null;
|
||||
}
|
||||
$this->attributes['cost'] = $value;
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class CheckoutAcceptance extends Model
|
||||
{
|
||||
use SoftDeletes, Notifiable;
|
||||
use HasFactory, SoftDeletes, Notifiable;
|
||||
|
||||
protected $casts = [
|
||||
'accepted_at' => 'datetime',
|
||||
|
|
|
@ -33,7 +33,8 @@ class Component extends SnipeModel
|
|||
'name' => 'required|min:3|max:255',
|
||||
'qty' => 'required|integer|min:1',
|
||||
'category_id' => 'required|integer|exists:categories,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'supplier_id' => 'nullable|integer|exists:suppliers,id',
|
||||
'company_id' => 'integer|nullable|exists:companies,id',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
|
@ -57,6 +58,7 @@ class Component extends SnipeModel
|
|||
protected $fillable = [
|
||||
'category_id',
|
||||
'company_id',
|
||||
'supplier_id',
|
||||
'location_id',
|
||||
'name',
|
||||
'purchase_cost',
|
||||
|
@ -86,6 +88,7 @@ class Component extends SnipeModel
|
|||
'category' => ['name'],
|
||||
'company' => ['name'],
|
||||
'location' => ['name'],
|
||||
'supplier' => ['name'],
|
||||
];
|
||||
|
||||
|
||||
|
@ -168,6 +171,18 @@ class Component extends SnipeModel
|
|||
return $this->belongsTo(\App\Models\Category::class, 'category_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the item -> supplier relationship
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function supplier()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the component -> action logs relationship
|
||||
*
|
||||
|
@ -247,4 +262,17 @@ class Component extends SnipeModel
|
|||
{
|
||||
return $query->leftJoin('companies', 'components.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on supplier
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param text $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderSupplier($query, $order)
|
||||
{
|
||||
return $query->leftJoin('suppliers', 'components.supplier_id', '=', 'suppliers.id')->orderBy('suppliers.name', $order);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ class Consumable extends SnipeModel
|
|||
'requestable' => 'boolean',
|
||||
'category_id' => 'integer',
|
||||
'company_id' => 'integer',
|
||||
'supplier_id',
|
||||
'qty' => 'integer',
|
||||
'min_amt' => 'integer',
|
||||
];
|
||||
|
@ -95,6 +96,7 @@ class Consumable extends SnipeModel
|
|||
'company' => ['name'],
|
||||
'location' => ['name'],
|
||||
'manufacturer' => ['name'],
|
||||
'supplier' => ['name'],
|
||||
];
|
||||
|
||||
|
||||
|
@ -249,6 +251,18 @@ class Consumable extends SnipeModel
|
|||
return $this->belongsToMany(\App\Models\User::class, 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the item -> supplier relationship
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function supplier()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether to send a checkin/checkout email based on
|
||||
|
@ -376,4 +390,17 @@ class Consumable extends SnipeModel
|
|||
{
|
||||
return $query->leftJoin('companies', 'consumables.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on supplier
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param text $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderSupplier($query, $order)
|
||||
{
|
||||
return $query->leftJoin('suppliers', 'consumables.supplier_id', '=', 'suppliers.id')->orderBy('suppliers.name', $order);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ class CustomField extends Model
|
|||
'name' => 'required|unique:custom_fields',
|
||||
'element' => 'required|in:text,listbox,textarea,checkbox,radio',
|
||||
'field_encrypted' => 'nullable|boolean',
|
||||
'auto_add_to_fieldsets' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -69,6 +70,8 @@ class CustomField extends Model
|
|||
'show_in_email',
|
||||
'is_unique',
|
||||
'display_in_user_view',
|
||||
'auto_add_to_fieldsets',
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -308,9 +311,9 @@ class CustomField extends Model
|
|||
$arr_parts = explode('|', $arr[$x]);
|
||||
if ($arr_parts[0] != '') {
|
||||
if (array_key_exists('1', $arr_parts)) {
|
||||
$result[$arr_parts[0]] = $arr_parts[1];
|
||||
$result[$arr_parts[0]] = trim($arr_parts[1]);
|
||||
} else {
|
||||
$result[$arr_parts[0]] = $arr_parts[0];
|
||||
$result[$arr_parts[0]] = trim($arr_parts[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,6 +213,7 @@ class Ldap extends Model
|
|||
$ldap_result_phone = Setting::getSettings()->ldap_phone;
|
||||
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
|
||||
$ldap_result_country = Setting::getSettings()->ldap_country;
|
||||
$ldap_result_location = Setting::getSettings()->ldap_location;
|
||||
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
||||
$ldap_result_manager = Setting::getSettings()->ldap_manager;
|
||||
// Get LDAP user data
|
||||
|
@ -227,6 +228,7 @@ class Ldap extends Model
|
|||
$item['country'] = $ldapattributes[$ldap_result_country][0] ?? '';
|
||||
$item['department'] = $ldapattributes[$ldap_result_dept][0] ?? '';
|
||||
$item['manager'] = $ldapattributes[$ldap_result_manager][0] ?? '';
|
||||
$item['location'] = $ldapattributes[$ldap_result_location][0] ?? '';
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
|
|
@ -33,9 +33,9 @@ class License extends Depreciable
|
|||
protected $table = 'licenses';
|
||||
|
||||
protected $casts = [
|
||||
'purchase_date' => 'datetime',
|
||||
'expiration_date' => 'datetime',
|
||||
'termination_date' => 'datetime',
|
||||
'purchase_date' => 'date',
|
||||
'expiration_date' => 'date',
|
||||
'termination_date' => 'date',
|
||||
'category_id' => 'integer',
|
||||
'company_id' => 'integer',
|
||||
];
|
||||
|
@ -49,9 +49,9 @@ class License extends Depreciable
|
|||
'category_id' => 'required|exists:categories,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'purchase_cost'=> 'numeric|nullable|gte:0',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||
'expiration_date' => 'date_format:Y-m-d|nullable',
|
||||
'termination_date' => 'date_format:Y-m-d|nullable',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -106,10 +106,10 @@ class License extends Depreciable
|
|||
* @var array
|
||||
*/
|
||||
protected $searchableRelations = [
|
||||
'manufacturer' => ['name'],
|
||||
'company' => ['name'],
|
||||
'category' => ['name'],
|
||||
'depreciation' => ['name'],
|
||||
'manufacturer' => ['name'],
|
||||
'company' => ['name'],
|
||||
'category' => ['name'],
|
||||
'depreciation' => ['name'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -425,7 +425,7 @@ class License extends Depreciable
|
|||
public static function assetcount()
|
||||
{
|
||||
return LicenseSeat::whereNull('deleted_at')
|
||||
->count();
|
||||
->count();
|
||||
}
|
||||
|
||||
|
||||
|
@ -441,8 +441,8 @@ class License extends Depreciable
|
|||
public function totalSeatsByLicenseID()
|
||||
{
|
||||
return LicenseSeat::where('license_id', '=', $this->id)
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,11 +486,12 @@ class License extends Depreciable
|
|||
public static function availassetcount()
|
||||
{
|
||||
return LicenseSeat::whereNull('assigned_to')
|
||||
->whereNull('asset_id')
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
->whereNull('asset_id')
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of total available seats for this license
|
||||
*
|
||||
|
@ -533,7 +534,7 @@ class License extends Depreciable
|
|||
{
|
||||
return $this->licenseSeatsRelation()->where(function ($query) {
|
||||
$query->whereNotNull('assigned_to')
|
||||
->orWhereNotNull('asset_id');
|
||||
->orWhereNotNull('asset_id');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -621,13 +622,13 @@ class License extends Depreciable
|
|||
public function freeSeat()
|
||||
{
|
||||
return $this->licenseseats()
|
||||
->whereNull('deleted_at')
|
||||
->where(function ($query) {
|
||||
$query->whereNull('assigned_to')
|
||||
->whereNull('asset_id');
|
||||
})
|
||||
->orderBy('id', 'asc')
|
||||
->first();
|
||||
->whereNull('deleted_at')
|
||||
->where(function ($query) {
|
||||
$query->whereNull('assigned_to')
|
||||
->whereNull('asset_id');
|
||||
})
|
||||
->orderBy('id', 'asc')
|
||||
->first();
|
||||
}
|
||||
|
||||
|
||||
|
@ -657,11 +658,11 @@ class License extends Depreciable
|
|||
$days = (is_null($days)) ? 60 : $days;
|
||||
|
||||
return self::whereNotNull('expiration_date')
|
||||
->whereNull('deleted_at')
|
||||
->whereRaw(DB::raw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) '))
|
||||
->where('expiration_date', '>', date('Y-m-d'))
|
||||
->orderBy('expiration_date', 'ASC')
|
||||
->get();
|
||||
->whereNull('deleted_at')
|
||||
->whereRaw(DB::raw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) '))
|
||||
->where('expiration_date', '>', date('Y-m-d'))
|
||||
->orderBy('expiration_date', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -705,4 +706,4 @@ class License extends Depreciable
|
|||
return $query->leftJoin('companies as companies', 'licenses.company_id', '=', 'companies.id')->select('licenses.*')
|
||||
->orderBy('companies.name', $order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,13 +6,15 @@ use App\Models\Traits\Acceptable;
|
|||
use App\Notifications\CheckinLicenseNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class LicenseSeat extends SnipeModel implements ICompanyableChild
|
||||
{
|
||||
use CompanyableChildTrait;
|
||||
use SoftDeletes;
|
||||
use HasFactory;
|
||||
use Loggable;
|
||||
use SoftDeletes;
|
||||
|
||||
protected $presenter = \App\Presenters\LicenseSeatPresenter::class;
|
||||
use Presentable;
|
||||
|
|
|
@ -26,11 +26,12 @@ class Location extends SnipeModel
|
|||
protected $table = 'locations';
|
||||
protected $rules = [
|
||||
'name' => 'required|min:2|max:255|unique_undeleted',
|
||||
'city' => 'min:2|max:255|nullable',
|
||||
'country' => 'min:2|max:255|nullable',
|
||||
'address' => 'max:80|nullable',
|
||||
'address2' => 'max:80|nullable',
|
||||
'zip' => 'min:3|max:10|nullable',
|
||||
'address' => 'max:191|nullable',
|
||||
'address2' => 'max:191|nullable',
|
||||
'city' => 'max:191|nullable',
|
||||
'state' => 'min:2|max:191|nullable',
|
||||
'country' => 'min:2|max:191|nullable',
|
||||
'zip' => 'max:10|nullable',
|
||||
'manager_id' => 'exists:users,id|nullable',
|
||||
'parent_id' => 'non_circular:locations,id',
|
||||
];
|
||||
|
@ -267,7 +268,7 @@ class Location extends SnipeModel
|
|||
|
||||
foreach ($locations_with_children[$parent_id] as $location) {
|
||||
$location->use_text = $prefix.' '.$location->name;
|
||||
$location->use_image = ($location->image) ? url('/').'/uploads/locations/'.$location->image : null;
|
||||
$location->use_image = ($location->image) ? config('app.url').'/uploads/locations/'.$location->image : null;
|
||||
$results[] = $location;
|
||||
//now append the children. (if we have any)
|
||||
if (array_key_exists($location->id, $locations_with_children)) {
|
||||
|
|
|
@ -23,8 +23,9 @@ class Manufacturer extends SnipeModel
|
|||
protected $rules = [
|
||||
'name' => 'required|min:2|max:255|unique:manufacturers,name,NULL,id,deleted_at,NULL',
|
||||
'url' => 'url|nullable',
|
||||
'support_url' => 'url|nullable',
|
||||
'support_email' => 'email|nullable',
|
||||
'support_url' => 'nullable|url',
|
||||
'warranty_lookup_url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://'
|
||||
];
|
||||
|
||||
protected $hidden = ['user_id'];
|
||||
|
@ -51,6 +52,7 @@ class Manufacturer extends SnipeModel
|
|||
'support_phone',
|
||||
'support_url',
|
||||
'url',
|
||||
'warranty_lookup_url',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
|
|
|
@ -76,6 +76,7 @@ class Setting extends Model
|
|||
'audit_interval' => 'numeric|nullable',
|
||||
'custom_forgot_pass_url' => 'url|nullable',
|
||||
'privacy_policy_link' => 'nullable|url',
|
||||
'google_client_id' => 'nullable|ends_with:apps.googleusercontent.com'
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
|
@ -86,6 +87,9 @@ class Setting extends Model
|
|||
'webhook_endpoint',
|
||||
'webhook_channel',
|
||||
'webhook_botname',
|
||||
'google_login',
|
||||
'google_client_id',
|
||||
'google_client_secret',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -341,7 +345,15 @@ class Setting extends Model
|
|||
'ad_domain',
|
||||
'ad_append_domain',
|
||||
'ldap_client_tls_key',
|
||||
'ldap_client_tls_cert'
|
||||
'ldap_client_tls_cert',
|
||||
'ldap_default_group',
|
||||
'ldap_dept',
|
||||
'ldap_emp_num',
|
||||
'ldap_phone_field',
|
||||
'ldap_jobtitle',
|
||||
'ldap_manager',
|
||||
'ldap_country',
|
||||
'ldap_location',
|
||||
])->first()->getAttributes();
|
||||
|
||||
return collect($ldapSettings);
|
||||
|
|
|
@ -21,9 +21,9 @@ class SnipeModel extends Model
|
|||
*/
|
||||
public function setPurchaseCostAttribute($value)
|
||||
{
|
||||
$value = Helper::ParseFloat($value);
|
||||
$value = Helper::ParseCurrency($value);
|
||||
|
||||
if ($value == '0.0') {
|
||||
if ($value == 0) {
|
||||
$value = null;
|
||||
}
|
||||
$this->attributes['purchase_cost'] = $value;
|
||||
|
|
|
@ -70,7 +70,11 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
|||
// Map a SCIM attribute to an attribute of the object.
|
||||
'mapping' => [
|
||||
|
||||
'id' => AttributeMapping::eloquent("id")->disableWrite(),
|
||||
'id' => (new AttributeMapping())->setRead(
|
||||
function (&$object) {
|
||||
return (string)$object->id;
|
||||
}
|
||||
)->disableWrite(),
|
||||
|
||||
'externalId' => AttributeMapping::eloquent('scim_externalid'), // FIXME - I have a PR that changes a lot of this.
|
||||
|
||||
|
@ -174,7 +178,6 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
|||
'$ref' => null,
|
||||
'display' => null,
|
||||
'type' => null,
|
||||
'type' => null
|
||||
]],
|
||||
|
||||
'entitlements' => null,
|
||||
|
|
|
@ -16,17 +16,17 @@ class Supplier extends SnipeModel
|
|||
protected $table = 'suppliers';
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|min:1|max:255|unique_undeleted',
|
||||
'address' => 'max:250|nullable',
|
||||
'address2' => 'max:250|nullable',
|
||||
'city' => 'max:255|nullable',
|
||||
'state' => 'max:32|nullable',
|
||||
'country' => 'max:3|nullable',
|
||||
'name' => 'required|min:1|max:255|unique_undeleted',
|
||||
'fax' => 'min:7|max:35|nullable',
|
||||
'phone' => 'min:7|max:35|nullable',
|
||||
'contact' => 'max:100|nullable',
|
||||
'notes' => 'max:191|nullable', // Default string length is 191 characters..
|
||||
'email' => 'email|max:150|nullable',
|
||||
'address' => 'max:250|nullable',
|
||||
'address2' => 'max:250|nullable',
|
||||
'city' => 'max:191|nullable',
|
||||
'state' => 'min:2|max:191|nullable',
|
||||
'country' => 'min:2|max:191|nullable',
|
||||
'zip' => 'max:10|nullable',
|
||||
'url' => 'sometimes|nullable|string|max:250',
|
||||
];
|
||||
|
@ -78,24 +78,7 @@ class Supplier extends SnipeModel
|
|||
{
|
||||
return $this->hasMany(Asset::class)->whereNull('deleted_at')->selectRaw('supplier_id, count(*) as count')->groupBy('supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the license seat count attribute
|
||||
*
|
||||
* @todo I don't see the licenseSeatsRelation here?
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v1.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function getLicenseSeatsCountAttribute()
|
||||
{
|
||||
if ($this->licenseSeatsRelation->first()) {
|
||||
return $this->licenseSeatsRelation->first()->count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the supplier -> assets relationship
|
||||
|
@ -121,6 +104,30 @@ class Supplier extends SnipeModel
|
|||
return $this->hasMany(\App\Models\Accessory::class, 'supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the supplier -> component relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function components()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Component::class, 'supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the supplier -> component relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.1.1]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function consumables()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Consumable::class, 'supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the supplier -> asset maintenances relationship
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Models\Traits;
|
|||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* This trait allows for cleaner searching of models,
|
||||
|
@ -164,7 +165,13 @@ trait Searchable
|
|||
}
|
||||
// I put this here because I only want to add the concat one time in the end of the user relation search
|
||||
if($relation == 'user') {
|
||||
$query->orWhereRaw('CONCAT (users.first_name, " ", users.last_name) LIKE ?', ["%{$term}%"]);
|
||||
$query->orWhereRaw(
|
||||
$this->buildMultipleColumnSearch([
|
||||
'users.first_name',
|
||||
'users.last_name',
|
||||
]),
|
||||
["%{$term}%"]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -257,4 +264,37 @@ trait Searchable
|
|||
|
||||
return $related->getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a search string for either MySQL or sqlite by separating the provided columns with a space.
|
||||
*
|
||||
* @param array $columns Columns to include in search string.
|
||||
* @return string
|
||||
*/
|
||||
private function buildMultipleColumnSearch(array $columns): string
|
||||
{
|
||||
$mappedColumns = collect($columns)->map(fn($column) => DB::getTablePrefix() . $column)->toArray();
|
||||
|
||||
$driver = config('database.connections.' . config('database.default') . '.driver');
|
||||
|
||||
if ($driver === 'sqlite') {
|
||||
return implode("||' '||", $mappedColumns) . ' LIKE ?';
|
||||
}
|
||||
|
||||
// Default to MySQL's concatenation method
|
||||
return 'CONCAT(' . implode('," ",', $mappedColumns) . ') LIKE ?';
|
||||
}
|
||||
|
||||
/**
|
||||
* Search a string across multiple columns separated with a space.
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param array $columns - Columns to include in search string.
|
||||
* @param $term
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeOrWhereMultipleColumns($query, array $columns, $term)
|
||||
{
|
||||
return $query->orWhereRaw($this->buildMultipleColumnSearch($columns), ["%{$term}%"]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
'avatar',
|
||||
'gravatar',
|
||||
'vip',
|
||||
'autoassign_licenses',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
@ -73,18 +74,12 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
'location_id' => 'integer',
|
||||
'company_id' => 'integer',
|
||||
'vip' => 'boolean',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
'autoassign_licenses' => 'boolean',
|
||||
];
|
||||
|
||||
|
||||
protected $dates = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
'start_date' => 'date_format:Y-m-d',
|
||||
'end_date' => 'date_format:Y-m-d',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Model validation rules
|
||||
*
|
||||
|
@ -102,6 +97,12 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
'location_id' => 'exists:locations,id|nullable',
|
||||
'start_date' => 'nullable|date_format:Y-m-d',
|
||||
'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:start_date',
|
||||
'autoassign_licenses' => 'boolean',
|
||||
'address' => 'max:191|nullable',
|
||||
'city' => 'max:191|nullable',
|
||||
'state' => 'min:2|max:191|nullable',
|
||||
'country' => 'min:2|max:191|nullable',
|
||||
'zip' => 'max:10|nullable',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -263,20 +264,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
return $this->last_name.', '.$this->first_name.' ('.$this->username.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for slack notifications.
|
||||
* Used by Notifiable trait.
|
||||
* @return mixed
|
||||
*/
|
||||
public function routeNotificationForSlack()
|
||||
{
|
||||
// At this point the endpoint is the same for everything.
|
||||
// In the future this may want to be adapted for individual notifications.
|
||||
$this->endpoint = \App\Models\Setting::getSettings()->webhook_endpoint;
|
||||
|
||||
return $this->endpoint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the user -> assets relationship
|
||||
|
@ -657,14 +644,14 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
*/
|
||||
public function scopeSimpleNameSearch($query, $search)
|
||||
{
|
||||
$query = $query->where('first_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('last_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%{$search}%"]);
|
||||
|
||||
return $query;
|
||||
return $query->where('first_name', 'LIKE', '%' . $search . '%')
|
||||
->orWhere('last_name', 'LIKE', '%' . $search . '%')
|
||||
->orWhereMultipleColumns([
|
||||
'users.first_name',
|
||||
'users.last_name',
|
||||
], $search);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run additional, advanced searches.
|
||||
*
|
||||
|
@ -673,9 +660,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function advancedTextSearch(Builder $query, array $terms) {
|
||||
|
||||
foreach($terms as $term) {
|
||||
$query = $query->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%{$term}%"]);
|
||||
$query->orWhereMultipleColumns([
|
||||
'users.first_name',
|
||||
'users.last_name',
|
||||
], $term);
|
||||
}
|
||||
|
||||
return $query;
|
||||
|
|
|
@ -23,6 +23,7 @@ class AuditNotification extends Notification
|
|||
public function __construct($params)
|
||||
{
|
||||
//
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
|
@ -43,9 +44,12 @@ class AuditNotification extends Notification
|
|||
|
||||
public function toSlack()
|
||||
{
|
||||
$channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : '';
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->content(class_basename(get_class($this->params['item'])).' Audited')
|
||||
->from(($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot')
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) {
|
||||
$item = $this->params['item'];
|
||||
$admin_user = $this->params['admin'];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue