Compare commits

..

23 Commits

Author SHA1 Message Date
snipe 6f233bc218 Get more of the select2 ajax lists working 2025-11-03 15:38:43 +00:00
snipe 448f4b94af Remove classes 2025-11-03 14:03:31 +00:00
snipe 7c58fb93a9 Fixed test 2025-11-01 02:53:47 +00:00
snipe 80e4e4a40e Updated more form fields 2025-11-01 02:45:59 +00:00
snipe 7161d56ae2 Prod assets for some reason 2025-10-31 19:07:17 +00:00
snipe 1e85c7b575 Put the form-control-static back since it didn’t cut down the number of files :( 2025-10-31 19:05:36 +00:00
snipe 03130f0947 Try to undo the asset stuff for the PR 2025-10-31 19:03:50 +00:00
snipe 4812e25e5c Added name awareness in child elements 2025-10-31 19:03:19 +00:00
snipe e6c49da11c Use new blade for textarea 2025-10-31 19:02:54 +00:00
snipe 6f3ee1914a Updated maintenances screen 2025-10-31 19:02:39 +00:00
snipe 9232ee781e Updated validation JS for select2 2025-10-31 19:02:25 +00:00
snipe 3d675d375c Re-add the form static so it’s less noisy for this PR 2025-10-31 19:02:02 +00:00
snipe d2edc77197 Debugging - remove later 2025-10-31 19:01:42 +00:00
snipe 53716cbe90 Still not working (pre-selecting the ID of the asset) 2025-10-31 19:00:55 +00:00
snipe 8ce3fe0df0 Pass name to input 2025-10-31 16:21:41 +00:00
snipe affee0a990 Handle unfilled data 2025-10-31 16:21:22 +00:00
snipe 6d5f515f48 Make select2 ajax a little more flexible 2025-10-31 12:23:08 +00:00
snipe d96844498f This doesn’t actually work yet 2025-10-31 12:22:56 +00:00
snipe 08609d4f56 Moar refactorings 2025-10-30 22:26:21 +00:00
snipe be344c440f Different approach - rely on nested slots 2025-10-30 21:30:10 +00:00
snipe 96cc2c9ee9 Move form into its own component 2025-10-30 16:35:15 +00:00
snipe fb1a89442c Removed p-static class 2025-10-30 14:10:06 +00:00
snipe 359e0197bf Start building out the box+form stuff 2025-10-30 14:02:33 +00:00
1480 changed files with 24350 additions and 177096 deletions
-27
View File
@@ -4235,33 +4235,6 @@
"contributions": [
"code"
]
},
{
"login": "smarsching",
"name": "Sebastian Marsching",
"avatar_url": "https://avatars.githubusercontent.com/u/2880129?v=4",
"profile": "http://sebastian.marsching.com/",
"contributions": [
"code"
]
},
{
"login": "mohammad-ahmadi1",
"name": "Mo",
"avatar_url": "https://avatars.githubusercontent.com/u/40658372?v=4",
"profile": "https://github.com/mohammad-ahmadi1",
"contributions": [
"code"
]
},
{
"login": "MarvelousAnything",
"name": "Owen V. Hayes",
"avatar_url": "https://avatars.githubusercontent.com/u/20994684?v=4",
"profile": "https://github.com/MarvelousAnything",
"contributions": [
"code"
]
}
]
}
-4
View File
@@ -137,8 +137,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null
# --------------------------------------------
@@ -149,8 +147,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null
# --------------------------------------------
-4
View File
@@ -144,8 +144,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null
# --------------------------------------------
@@ -156,8 +154,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null
# --------------------------------------------
+1 -19
View File
@@ -40,26 +40,12 @@ DB_SANITIZE_BY_DEFAULT=false
# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS
# --------------------------------------------
# Enable SSL connection to database (true/false)
DB_SSL=false
# Set to true for cloud databases like AWS RDS, Azure Database, Google Cloud SQL
# Set to false for self-hosted databases with client certificates
DB_SSL_IS_PAAS=false
# Required when DB_SSL_IS_PAAS=false (client certificate authentication)
DB_SSL_KEY_PATH=null
DB_SSL_CERT_PATH=null
# Path to CA certificate bundle (required for SSL connections)
# For AWS RDS, download from: https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
DB_SSL_CA_PATH=null
# SSL cipher (optional, leave null for default)
DB_SSL_CIPHER=null
# Verify server certificate (true/false, defaults to false if not set)
# Set to false for development or when using self-signed certificates
DB_SSL_VERIFY_SERVER=null
# --------------------------------------------
@@ -157,8 +143,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null
# --------------------------------------------
@@ -169,8 +153,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null
# --------------------------------------------
@@ -215,7 +197,7 @@ REPORT_TIME_LIMIT=12000
API_THROTTLE_PER_MINUTE=120
CSV_ESCAPE_FORMULAS=true
LIVEWIRE_URL_PREFIX=null
MAX_UNPAGINATED=5000
# --------------------------------------------
# OPTIONAL: SAML SETTINGS
+3 -4
View File
@@ -1,11 +1,10 @@
frontend: ["*.js", "*.css", "*.scss", "*.less", "*.blade.*", "resources/views/livewire/*","resources/views/layouts/default.blade.php"]
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*", "resources/views/livewire/*"]
skins: ["*.js", "*.css", "*.scss", "*.less"]
css: ["*.css","*.scss", "*.less"]
javascript: ["*.js", "package.json", "package.lock"]
backend: ["/app/*", "composer.json", "composer.lock"]
translations: ["/resources/lang/*"]
translations: ["/resources/lang"]
livewire: ["/app/Http/Livewire/*", "resources/views/livewire/*"]
blade-components: ["resources/views/blade/*"]
backups: ["*backup*"]
restore: ["*restore*"]
saml: ["*saml*"]
@@ -17,7 +16,7 @@ api: ["/app/Http/Controllers/Api/*"]
notifications: ["/app/Notifications/*"]
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", "/resources/views/users/ldap.blade.php","/resources/views/settings/ldap.blade.php"]
LDAP: ["*Ldap*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
tests: ["/tests/*", "/database/factories/*", "/stubs"]
config: .github
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
language: [ 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v5
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Crowdin push
uses: crowdin/github-action@v2
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v6
uses: actions/checkout@v5
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v6
uses: actions/checkout@v5
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
dockerHubDescription:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Docker Hub Description
uses: grokability/dockerhub-description@7ea9d275c7cdbe2b676a093a0308c50665e3b8b4
+3 -3
View File
@@ -37,13 +37,13 @@ jobs:
php-version: "${{ matrix.php-version }}"
coverage: none
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v5
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -82,7 +82,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
+3 -3
View File
@@ -34,13 +34,13 @@ jobs:
php-version: "${{ matrix.php-version }}"
coverage: none
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v5
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -81,7 +81,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
+3 -3
View File
@@ -25,13 +25,13 @@ jobs:
php-version: "${{ matrix.php-version }}"
coverage: none
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v5
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -67,7 +67,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |
+1 -2
View File
@@ -68,8 +68,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/181059?v=4" width="110px;"/><br /><sub>Juan Font</sub>](https://github.com/juanfont)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juanfont "Code") | [<img src="https://avatars.githubusercontent.com/u/13137708?v=4" width="110px;"/><br /><sub>Juho Taipale</sub>](https://github.com/juhotaipale)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juhotaipale "Code") | [<img src="https://avatars.githubusercontent.com/u/1007419?v=4" width="110px;"/><br /><sub>Korvin Szanto</sub>](https://github.com/KorvinSzanto)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KorvinSzanto "Code") | [<img src="https://avatars.githubusercontent.com/u/8513053?v=4" width="110px;"/><br /><sub>Lewis Foster</sub>](https://lewisfoster.foo/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sniff122 "Code") | [<img src="https://avatars.githubusercontent.com/u/33877541?v=4" width="110px;"/><br /><sub>Logan Swartzendruber</sub>](https://github.com/loganswartz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=loganswartz "Code") | [<img src="https://avatars.githubusercontent.com/u/1156208?v=4" width="110px;"/><br /><sub>Lorenzo P.</sub>](https://github.com/lopezio)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lopezio "Code") | [<img src="https://avatars.githubusercontent.com/u/33946590?v=4" width="110px;"/><br /><sub>Lukas Jung</sub>](https://github.com/m4us1ne)<br />[💻](https://github.com/snipe/snipe-it/commits?author=m4us1ne "Code") |
| [<img src="https://avatars.githubusercontent.com/u/10965027?v=4" width="110px;"/><br /><sub>Ellie</sub>](https://leafedfox.xyz/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeafedFox "Code") | [<img src="https://avatars.githubusercontent.com/u/20960555?v=4" width="110px;"/><br /><sub>GA Stamper</sub>](https://github.com/gastamper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gastamper "Code") | [<img src="https://avatars.githubusercontent.com/u/206553556?v=4" width="110px;"/><br /><sub>Guillaume Lefranc</sub>](https://github.com/gl-pup)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gl-pup "Code") | [<img src="https://avatars.githubusercontent.com/u/733892?v=4" width="110px;"/><br /><sub>Hajo Möller</sub>](https://github.com/dasjoe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dasjoe "Code") | [<img src="https://avatars.githubusercontent.com/u/3420063?v=4" width="110px;"/><br /><sub>Istvan Basa</sub>](https://github.com/pottom)<br />[💻](https://github.com/snipe/snipe-it/commits?author=pottom "Code") | [<img src="https://avatars.githubusercontent.com/u/810824?v=4" width="110px;"/><br /><sub>JJ Asghar</sub>](https://jjasghar.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jjasghar "Code") | [<img src="https://avatars.githubusercontent.com/u/40404495?v=4" width="110px;"/><br /><sub>James E. Msenga</sub>](https://github.com/JemCdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JemCdo "Code") |
| [<img src="https://avatars.githubusercontent.com/u/6865786?v=4" width="110px;"/><br /><sub>Jan Felix Wiebe</sub>](https://github.com/jfwiebe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jfwiebe "Code") | [<img src="https://avatars.githubusercontent.com/u/43412008?v=4" width="110px;"/><br /><sub>Jo Drexl</sub>](https://www.nfon.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=drexljo "Code") | [<img src="https://avatars.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>Austin Sasko</sub>](https://github.com/austinsasko)<br />[💻](https://github.com/snipe/snipe-it/commits?author=austinsasko "Code") | [<img src="https://avatars.githubusercontent.com/u/4875039?v=4" width="110px;"/><br /><sub>Jasson</sub>](http://jassoncordones.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JassonCordones "Code") | [<img src="https://avatars.githubusercontent.com/u/76069640?v=4" width="110px;"/><br /><sub>Okean</sub>](https://github.com/Tinyblargon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tinyblargon "Code") | [<img src="https://avatars.githubusercontent.com/u/6515064?v=4" width="110px;"/><br /><sub>Alejandro Medrano</sub>](https://www.lst.tfo.upm.es/alejandro-medrano/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=amedranogil "Code") | [<img src="https://avatars.githubusercontent.com/u/58696401?v=4" width="110px;"/><br /><sub>Lukas Kraic</sub>](https://github.com/lukaskraic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukaskraic "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1571724?v=4" width="110px;"/><br /><sub>Герхард PICCORO Lenz McKAY </sub>](https://github-readme-stats.vercel.app/api?username=mckaygerhard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mckaygerhard "Code") | [<img src="https://avatars.githubusercontent.com/u/15015119?v=4" width="110px;"/><br /><sub>Johannes Pollitt</sub>](https://github.com/FlorestanII)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorestanII "Code") | [<img src="https://avatars.githubusercontent.com/u/14185442?v=4" width="110px;"/><br /><sub>Michael Strobel</sub>](https://strobelm.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=strobelm "Code") | [<img src="https://avatars.githubusercontent.com/u/634790?v=4" width="110px;"/><br /><sub>Nicky West</sub>](http://nickwest.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nickwest "Code") | [<img src="https://avatars.githubusercontent.com/u/1347327?v=4" width="110px;"/><br /><sub>akaspeh1</sub>](https://github.com/akaspeh1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akaspeh1 "Code") | [<img src="https://avatars.githubusercontent.com/u/2880129?v=4" width="110px;"/><br /><sub>Sebastian Marsching</sub>](http://sebastian.marsching.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=smarsching "Code") | [<img src="https://avatars.githubusercontent.com/u/40658372?v=4" width="110px;"/><br /><sub>Mo</sub>](https://github.com/mohammad-ahmadi1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mohammad-ahmadi1 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/20994684?v=4" width="110px;"/><br /><sub>Owen V. Hayes</sub>](https://github.com/MarvelousAnything)<br />[💻](https://github.com/snipe/snipe-it/commits?author=MarvelousAnything "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1571724?v=4" width="110px;"/><br /><sub>Герхард PICCORO Lenz McKAY </sub>](https://github-readme-stats.vercel.app/api?username=mckaygerhard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mckaygerhard "Code") | [<img src="https://avatars.githubusercontent.com/u/15015119?v=4" width="110px;"/><br /><sub>Johannes Pollitt</sub>](https://github.com/FlorestanII)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorestanII "Code") | [<img src="https://avatars.githubusercontent.com/u/14185442?v=4" width="110px;"/><br /><sub>Michael Strobel</sub>](https://strobelm.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=strobelm "Code") | [<img src="https://avatars.githubusercontent.com/u/634790?v=4" width="110px;"/><br /><sub>Nicky West</sub>](http://nickwest.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nickwest "Code") | [<img src="https://avatars.githubusercontent.com/u/1347327?v=4" width="110px;"/><br /><sub>akaspeh1</sub>](https://github.com/akaspeh1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akaspeh1 "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
+30 -30
View File
@@ -1,35 +1,35 @@
FROM alpine:3.23
FROM alpine:3.19
# Apache + PHP
RUN apk add --no-cache \
apache2 \
php84 \
php84-common \
php84-apache2 \
php84-curl \
php84-ldap \
php84-mysqli \
php84-gd \
php84-xml \
php84-mbstring \
php84-zip \
php84-ctype \
php84-tokenizer \
php84-pdo_mysql \
php84-openssl \
php84-bcmath \
php84-phar \
php84-json \
php84-iconv \
php84-fileinfo \
php84-simplexml \
php84-session \
php84-dom \
php84-xmlwriter \
php84-xmlreader \
php84-sodium \
php84-redis \
php84-pecl-memcached \
php84-exif \
php82 \
php82-common \
php82-apache2 \
php82-curl \
php82-ldap \
php82-mysqli \
php82-gd \
php82-xml \
php82-mbstring \
php82-zip \
php82-ctype \
php82-tokenizer \
php82-pdo_mysql \
php82-openssl \
php82-bcmath \
php82-phar \
php82-json \
php82-iconv \
php82-fileinfo \
php82-simplexml \
php82-session \
php82-dom \
php82-xmlwriter \
php82-xmlreader \
php82-sodium \
php82-redis \
php82-pecl-memcached \
php82-exif \
curl \
wget \
vim \
@@ -42,7 +42,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/php84/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php82/php.ini
COPY docker/000-default-2.4.conf /etc/apache2/conf.d/default.conf
# Enable mod_rewrite
-3
View File
@@ -78,14 +78,11 @@ Since the release of the JSON REST API, several third-party developers have been
#### Libraries & Modules
- [SnipeScheduler](https://github.com/JSY-Ben/SnipeScheduler) by [@JSY-Ben](https://github.com/JSY-Ben) - An Asset Reservation/Checkout System for Snipe-IT
- [Snipe-IT MCP Server](https://github.com/jameshgordy/snipeit-mcp) by [@jameshgordy](https://github.com/jameshgordy) - A Model Context Protocol (MCP) server for managing Snipe-IT inventory systems
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
- [jamf-snipe-rename](https://macblog.org/jamf-snipe-rename/) - Python script to rename computers in Jamf from Snipe-IT
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
- [Rudder2Snipe](https://github.com/norbertoaquino/rudder2snipe) by [@norbertoaquino](https://github.com/norbertoaquino) - Rudder.io integration for Snipe-IT
- [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.
+20 -21
View File
@@ -245,26 +245,26 @@ class LdapSync extends Command
// Assign the mapped LDAP attributes for each user to the Snipe-IT user fields
for ($i = 0; $i < $results['count']; $i++) {
$item = [];
$item['username'] = $results[$i][$ldap_map["username"]][0] ?? null;
$item['display_name'] = $results[$i][$ldap_map["display_name"]][0] ?? null;
$item['employee_number'] = $results[$i][$ldap_map["emp_num"]][0] ?? null;
$item['lastname'] = $results[$i][$ldap_map["last_name"]][0] ?? null;
$item['firstname'] = $results[$i][$ldap_map["first_name"]][0] ?? null;
$item['email'] = $results[$i][$ldap_map["email"]][0] ?? null;
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? null;
$item['location_id'] = $results[$i]['location_id'] ?? null;
$item['telephone'] = $results[$i][$ldap_map["phone"]][0] ?? null;
$item['mobile'] = $results[$i][$ldap_map["mobile"]][0] ?? null;
$item['jobtitle'] = $results[$i][$ldap_map["jobtitle"]][0] ?? null;
$item['address'] = $results[$i][$ldap_map["address"]][0] ?? null;
$item['city'] = $results[$i][$ldap_map["city"]][0] ?? null;
$item['state'] = $results[$i][$ldap_map["state"]][0] ?? null;
$item['country'] = $results[$i][$ldap_map["country"]][0] ?? null;
$item['zip'] = $results[$i][$ldap_map["zip"]][0] ?? null;
$item['department'] = $results[$i][$ldap_map["dept"]][0] ?? null;
$item['manager'] = $results[$i][$ldap_map["manager"]][0] ?? null;
$item['location'] = $results[$i][$ldap_map["location"]][0] ?? null;
$location = $default_location; //initially, set '$location' to the default_location (which may just be null)
$item['username'] = $results[$i][$ldap_map["username"]][0] ?? '';
$item['display_name'] = $results[$i][$ldap_map["display_name"]][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_map["emp_num"]][0] ?? '';
$item['lastname'] = $results[$i][$ldap_map["last_name"]][0] ?? '';
$item['firstname'] = $results[$i][$ldap_map["first_name"]][0] ?? '';
$item['email'] = $results[$i][$ldap_map["email"]][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_map["phone"]][0] ?? '';
$item['mobile'] = $results[$i][$ldap_map["mobile"]][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_map["jobtitle"]][0] ?? '';
$item['address'] = $results[$i][$ldap_map["address"]][0] ?? '';
$item['city'] = $results[$i][$ldap_map["city"]][0] ?? '';
$item['state'] = $results[$i][$ldap_map["state"]][0] ?? '';
$item['country'] = $results[$i][$ldap_map["country"]][0] ?? '';
$item['zip'] = $results[$i][$ldap_map["zip"]][0] ?? '';
$item['department'] = $results[$i][$ldap_map["dept"]][0] ?? '';
$item['manager'] = $results[$i][$ldap_map["manager"]][0] ?? '';
$item['location'] = $results[$i][$ldap_map["location"]][0] ?? '';
$location = $default_location; //initially, set '$location' to the default_location (which may just be `null`)
// ONLY if you are using the "ldap_location" option *AND* you have an actual result
if ($ldap_map["location"] && $item['location']) {
@@ -464,7 +464,6 @@ class LdapSync extends Command
$errors = '';
if ($user->save()) {
$item['id'] = $user->id;
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
if ($item['createorupdate'] === 'created' && $ldap_default_group) {
@@ -1,74 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Enums\ActionType;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class MigrateLicenseSeatQuantitiesInActionLogs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:migrate-license-seat-quantities-in-action-logs
{--no-interaction: Do not ask any interactive question}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Updates quantity field in action_logs table for license seats that were added or deleted.';
/**
* Execute the console command.
*/
public function handle()
{
$query = DB::table('action_logs')
->whereIn('action_type', [
ActionType::AddSeats->value,
ActionType::DeleteSeats->value,
])
->where('quantity', '=', 1)
->orderBy('id');
$count = $query->count();
if ($count === 0) {
$this->info('Nothing to update');
return 0;
}
$this->info("{$count} logs to update");
if ($this->option('no-interaction') || $this->confirm('Update quantities in the action log?')) {
$query->chunk(50, function ($logs) {
$logs->each(function ($log) {
$quantityFromNote = Str::between($log->note, "ed ", " seats");
if (!is_numeric($quantityFromNote)) {
$this->error('Could not parse quantity from ID: {id}', ['id' => $log->id]);
}
if ($log->quantity !== (int) $quantityFromNote) {
$this->info(vsprintf('Updating id: %s to quantity %s', [
'id' => $log->id,
'new_quantity' => $quantityFromNote,
]));
DB::table('action_logs')->where('id', $log->id)->update(['quantity' => (int) $quantityFromNote]);
}
});
});
}
return 0;
}
}
+6 -13
View File
@@ -33,11 +33,6 @@ class ObjectImportCommand extends Command
*/
protected ProgressIndicator $progressIndicator;
/**
* Logger instance with configurable log path
*/
protected $logger;
/**
* Create a new command instance.
*
@@ -61,7 +56,7 @@ class ObjectImportCommand extends Command
$this->progressIndicator = new ProgressIndicator($this->output);
$filename = $this->argument('filename');
$class = ucfirst($this->option('item-type'));
$class = title_case($this->option('item-type'));
$classString = "App\\Importer\\{$class}Importer";
$importer = new $classString($filename);
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
@@ -70,11 +65,9 @@ class ObjectImportCommand extends Command
->setShouldNotify($this->option('send-welcome'))
->setUsernameFormat($this->option('username_format'));
$this->logger = Log::build([
'driver' => 'single',
'path' => $this->option('logfile'),
]);
// This $logFile/useFiles() bit is currently broken, so commenting it out for now
// $logFile = $this->option('logfile');
// Log::useFiles($logFile);
$this->progressIndicator->start('======= Importing Items from '.$filename.' =========');
$importer->import();
@@ -106,10 +99,10 @@ class ObjectImportCommand extends Command
public function log($string, $level = 'info')
{
if ($level === 'warning') {
$this->logger->warning($string);
Log::warning($string);
$this->comment($string);
} else {
$this->logger->Info($string);
Log::Info($string);
if ($this->option('verbose')) {
$this->comment($string);
}
-132
View File
@@ -1,132 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Models\CheckoutAcceptance;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class PurgeEulaPDFs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:purge-eula-pdfs
{--older-than-days= : The number of days we should delete before }
{--force : Skip the interactive yes/no prompt for confirmation}
{--dryrun : Show the records that would be deleted but don\'t update the database or delete files from disk}
{--with-output : Display the results in a table in your console}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This purges signature files and EULAs from the system if they are older than the date passed with --older-than-days=.';
/**
* Execute the console command.
*/
public function handle()
{
$before = $this->option('older-than-days');
if (($before=='') || (!is_numeric($before))) {
return $this->error('ERROR: You must pass a valid number for --older-than-days (example: snipeit:purge-eula-pdfs --older-than-days=365.)');
}
$interval_date = Carbon::now()->subDays($before);
$signature_path = 'private_uploads/signatures/';
$eula_path = 'private_uploads/eula-pdfs/';
if (!Storage::exists($eula_path)) {
$this->fail('The storage directory "'.$eula_path.'" does not exist. No EULA files will be deleted.');
}
if (!Storage::exists($signature_path)) {
$this->fail('The storage directory "'.$signature_path.'" does not exist. No signature files will be deleted.');
}
if ($this->option('dryrun')) {
$this->info('This script is being run with the --dryrun option. No files or records will be deleted.');
}
$acceptances = CheckoutAcceptance::HasFiles()->where('updated_at','<', $interval_date)->with('assignedTo')->get();
if (!$this->option('force')) {
if ($this->confirm("\n****************************************************\nTHIS WILL DELETE ALL OF THE SIGNATURES AND EULA PDF FILES SINCE $interval_date. \nThere is NO undo! \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) {
}
}
if ($acceptances->count() == 0) {
return $this->warn('There are no item acceptances with signatures or EULA PDFs from before '.$interval_date);
}
$this->info(number_format($acceptances->count()) . ' EULA PDFs from before '.$interval_date.' will be purged');
if (!$this->option('with-output')) {
$this->info('Run this command with the --with-output option to see the full list in the console.');
} else {
$this->table(
[
trans('general.user'),
trans('general.type'),
trans('general.item'),
trans('general.category'),
trans('general.accepted_date'),
trans('general.declined_date'),
trans('general.signature'),
trans('general.filename'),
],
$acceptances->map(fn($acceptance) => [
trans('general.user') => $acceptance->assignedTo->display_name,
trans('general.type') => $acceptance->display_checkoutable_type,
trans('general.item') => $acceptance->checkoutable_type::find($acceptance->checkoutable_id)->display_name,
trans('general.category') => $acceptance->checkoutable_category_name,
trans('general.accepted_date') => $acceptance->accepted_at,
trans('general.declined_date') => $acceptance->declined_at,
trans('general.signature') => $acceptance->signature_filename,
trans('general.filename') => $acceptance->stored_eula_file,
])
);
}
foreach ($acceptances as $acceptance) {
$signature_file = $signature_path.$acceptance->signature_filename;
$eula_file = $eula_path.$acceptance->stored_eula_file;
if (Storage::exists($signature_file)) {
if (!$this->option('dryrun')) {
Storage::delete($signature_file);
}
} else {
$this->error('The file "'. $signature_file.'" does not exist.');
}
if (Storage::exists($eula_file)) {
if (!$this->option('dryrun')) {
Storage::delete($eula_file);
}
} else {
$this->error('The file "'.$eula_file.'" does not exist.');
}
if (!$this->option('dryrun')) {
$acceptance->delete();
}
}
}
}
+2 -5
View File
@@ -49,15 +49,14 @@ class ResetDemoSettings extends Command
$settings->logo = 'snipe-logo.png';
$settings->alert_email = 'service@snipe-it.io';
$settings->login_note = 'Use `admin` / `password` to login to the demo.';
$settings->header_color = '#3c8dbc';
$settings->link_dark_color = '#5fa4cc';
$settings->link_light_color = '#296282;';
$settings->header_color = null;
$settings->label2_2d_type = 'QRCODE';
$settings->default_currency = 'USD';
$settings->brand = 2;
$settings->ldap_enabled = 0;
$settings->full_multiple_companies_support = 0;
$settings->label2_1d_type = 'C128';
$settings->skin = '';
$settings->email_domain = 'snipeitapp.com';
$settings->email_format = 'filastname';
$settings->username_format = 'filastname';
@@ -81,8 +80,6 @@ class ResetDemoSettings extends Command
if ($user = User::where('username', '=', 'admin')->first()) {
$user->locale = 'en-US';
$user->enable_confetti = 1;
$user->enable_sounds = 1;
$user->save();
}
+1 -1
View File
@@ -52,7 +52,7 @@ class SQLStreamer {
/* we *could* have made the ^INSERT INTO blah VALUES$ turn on the capturing state, and closed it with
a ^(blahblah);$ but it's cleaner to not have to manage the state machine. We're just going to
assume that (blahblah), or (blahblah); are values for INSERT and are always acceptable. */
"<^/\*![0-9]{5} SET NAMES '?[a-zA-Z0-9_-]+'? \*/;$>" => false, //using weird delimiters (<,>) for readability. allow quoted or unquoted charsets
"<^/\*!40101 SET NAMES '?[a-zA-Z0-9_-]+'? \*/;$>" => false, //using weird delimiters (<,>) for readability. allow quoted or unquoted charsets
"<^/\*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' \*/;$>" => false, //same, now handle zero-values
];
+11 -27
View File
@@ -3,18 +3,13 @@
namespace App\Console\Commands;
use App\Mail\UnacceptedAssetReminderMail;
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\Setting;
use App\Models\User;
use App\Notifications\CheckoutAssetNotification;
use App\Notifications\CurrentInventory;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Facades\Mail;
class SendAcceptanceReminder extends Command
@@ -31,7 +26,7 @@ class SendAcceptanceReminder extends Command
*
* @var string
*/
protected $description = 'This will resend users with unaccepted items a reminder to accept or decline them.';
protected $description = 'This will resend users with unaccepted assets a reminder to accept or decline them.';
/**
* Create a new command instance.
@@ -50,30 +45,19 @@ class SendAcceptanceReminder extends Command
*/
public function handle()
{
$pending = CheckoutAcceptance::query()
->with([
'checkoutable' => function (MorphTo $morph) {
$morph->morphWith([
Asset::class => ['model.category', 'assignedTo', 'adminuser', 'company', 'checkouts'],
Accessory::class => ['category', 'company', 'checkouts'],
LicenseSeat::class => ['user', 'license', 'checkouts'],
Component::class => ['assignedTo', 'company', 'checkouts'],
Consumable::class => ['company', 'checkouts'],
]);
},
'assignedTo',
])
->whereHasMorph(
'checkoutable',
[Asset::class, Accessory::class, LicenseSeat::class, Component::class, Consumable::class],
fn ($q) => $q->whereNull('accepted_at')
->whereNull('declined_at')
)
->pending()
->get();
$pending = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')
->whereHas('checkoutable', function($query) {
$query->where('accepted_at', null)
->where('declined_at', null);
})
->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model', 'checkoutable.adminuser'])
->get();
$count = 0;
$unacceptedAssetGroups = $pending
->filter(function($acceptance) {
return $acceptance->checkoutable_type == 'App\Models\Asset';
})
->map(function($acceptance) {
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
})
@@ -9,8 +9,6 @@ use App\Notifications\ExpectedCheckinAdminNotification;
use App\Notifications\ExpectedCheckinNotification;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;
use App\Helpers\Helper;
class SendExpectedCheckinAlerts extends Command
{
@@ -19,7 +17,7 @@ class SendExpectedCheckinAlerts extends Command
*
* @var string
*/
protected $signature = 'snipeit:expected-checkin {--with-output : Display the results in a table in your console in addition to sending the email}';
protected $name = 'snipeit:expected-checkin';
/**
* The console command description.
@@ -44,47 +42,19 @@ class SendExpectedCheckinAlerts extends Command
public function handle()
{
$settings = Setting::getSettings();
$interval = $settings->due_checkin_days ?? 0;
$interval = $settings->audit_warning_days ?? 0;
$today = Carbon::now();
$interval_date = $today->copy()->addDays($interval);
$count = 0;
if (!$this->option('with-output')) {
$this->info('Run this command with the --with-output option to see the full list in the console.');
}
$assets = Asset::whereNull('deleted_at')->DueOrOverdueForCheckin($settings)->orderBy('assets.expected_checkin', 'desc')->get();
$this->info($assets->count().' assets must be checked on or before '.Helper::getFormattedDateObject($interval_date, 'date', false));
$this->info($assets->count().' assets must be checked in on or before '.$interval_date.' is deadline');
foreach ($assets as $asset) {
if ($asset->assignedTo && (isset($asset->assignedTo->email)) && ($asset->assignedTo->email!='') && $asset->checkedOutToUser()) {
$this->info('Sending User ExpectedCheckinNotification to: '.$asset->assignedTo->email);
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
$count++;
}
}
if ($this->option('with-output')) {
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
$this->table(
[
trans('general.id'),
trans('admin/hardware/form.tag'),
trans('admin/hardware/form.model'),
trans('general.model_no'),
trans('general.purchase_date'),
trans('admin/hardware/form.expected_checkin'),
],
$assets->map(fn($assets) => [
trans('general.id') => $assets->id,
trans('admin/hardware/form.tag') => $assets->asset_tag,
trans('admin/hardware/form.model') => $assets->model->name,
trans('general.model_no') => $assets->model->model_number,
trans('general.purchase_date') => $assets->purchase_date_formatted,
trans('admin/hardware/form.eol_date') => $assets->expected_checkin_formattedDate ? $assets->expected_checkin_formattedDate . ' (' . $assets->expected_checkin_diff_for_humans . ')' : '',
])
);
}
}
@@ -93,11 +63,10 @@ class SendExpectedCheckinAlerts extends Command
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
return new AlertRecipient($item);
});
Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
$this->info('Sending Admin ExpectedCheckinNotification to: '.$settings->alert_email);
\Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
}
$this->info('Sent checkin reminders to to '.$count.' users.');
}
}
@@ -14,11 +14,11 @@ use Illuminate\Support\Facades\Mail;
class SendExpirationAlerts extends Command
{
/**
* The name and signature of the console command.
*
* The console command name.
*
* @var string
*/
protected $signature = 'snipeit:expiring-alerts {--expired-licenses}';
protected $name = 'snipeit:expiring-alerts';
/**
* The console command description.
@@ -55,8 +55,6 @@ class SendExpirationAlerts extends Command
// Expiring Assets
$assets = Asset::getExpiringWarrantyOrEol($alert_interval);
$assets->load(['assignedTo', 'supplier']);
if ($assets->count() > 0) {
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
@@ -87,7 +85,7 @@ class SendExpirationAlerts extends Command
}
// Expiring licenses
$licenses = License::query()->ExpiringLicenses($alert_interval, $this->option('expired-licenses'))
$licenses = License::query()->ExpiringLicenses($alert_interval)
->with('manufacturer','category')
->orderBy('expiration_date', 'ASC')
->orderBy('termination_date', 'ASC')
+1 -3
View File
@@ -52,9 +52,7 @@ class SendInventoryAlerts extends Command
return new AlertRecipient($item);
});
Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
} else {
$this->info('No low inventory items found. No mail sent.');
\Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
}
} else {
if ($settings->alert_email == '') {
-33
View File
@@ -1,33 +0,0 @@
<?php
namespace App\Enums;
enum ActionType: string
{
// General
case Create = 'create';
case Update = 'update';
case Delete = 'delete';
case Restore = 'restore';
// Assets/Accessories/Components/Licenses/Consumables
case Checkout = 'checkout';
case CheckinFrom = 'checkin from';
case Requested = 'requested';
case RequestCanceled = 'request canceled';
case Accepted = 'accepted';
case Declined = 'declined';
case Audit = 'audit';
case NoteAdded = 'note added';
// Users
case TwoFactorReset = '2FA reset';
case Merged = 'merged';
// Licenses
case DeleteSeats = 'delete seats';
case AddSeats = 'add seats';
// File Uploads
case Uploaded = 'uploaded';
case UploadDeleted = 'upload deleted';
}
+1 -3
View File
@@ -15,20 +15,18 @@ class CheckoutableCheckedOut
public $checkedOutBy;
public $note;
public $originalValues;
public int $quantity;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [], $quantity = 1)
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [])
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedOutBy = $checkedOutBy;
$this->note = $note;
$this->originalValues = $originalValues;
$this->quantity = $quantity;
}
}
+10 -102
View File
@@ -2,7 +2,6 @@
namespace App\Helpers;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Component;
@@ -14,7 +13,6 @@ use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\License;
use App\Models\Location;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Contracts\Encryption\DecryptException;
@@ -778,7 +776,7 @@ class Helper
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
$accessories = Accessory::withCount('checkouts as checkouts_count')->whereNotNull('min_amt')->get();
$components = Component::whereNotNull('min_amt')->get();
$asset_models = AssetModel::where('min_amt', '>', 0)->withCount(['availableAssets', 'assets'])->get();
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
$licenses = License::where('min_amt', '>', 0)->get();
$items_array = [];
@@ -786,7 +784,7 @@ class Helper
foreach ($consumables as $consumable) {
$avail = $consumable->numRemaining();
if ($avail <= ($consumable->min_amt) + $alert_threshold) {
if ($avail < ($consumable->min_amt) + $alert_threshold) {
if ($consumable->qty > 0) {
$percent = number_format((($avail / $consumable->qty) * 100), 0);
} else {
@@ -805,7 +803,7 @@ class Helper
foreach ($accessories as $accessory) {
$avail = $accessory->qty - $accessory->checkouts_count;
if ($avail <= ($accessory->min_amt) + $alert_threshold) {
if ($avail < ($accessory->min_amt) + $alert_threshold) {
if ($accessory->qty > 0) {
$percent = number_format((($avail / $accessory->qty) * 100), 0);
} else {
@@ -824,7 +822,7 @@ class Helper
foreach ($components as $component) {
$avail = $component->numRemaining();
if ($avail <= ($component->min_amt) + $alert_threshold) {
if ($avail < ($component->min_amt) + $alert_threshold) {
if ($component->qty > 0) {
$percent = number_format((($avail / $component->qty) * 100), 0);
} else {
@@ -844,10 +842,10 @@ class Helper
foreach ($asset_models as $asset_model){
$asset = new Asset();
$total_owned = $asset_model->assets_count; //requires the withCount() clause in the initial query!
$avail = $asset_model->available_assets_count; //requires the withCount() clause in the initial query!
$total_owned = $asset->where('model_id', '=', $asset_model->id)->count();
$avail = $asset->where('model_id', '=', $asset_model->id)->whereNull('assigned_to')->count();
if ($avail <= ($asset_model->min_amt) + $alert_threshold) {
if ($avail < ($asset_model->min_amt) + $alert_threshold) {
if ($avail > 0) {
$percent = number_format((($avail / $total_owned) * 100), 0);
} else {
@@ -865,7 +863,7 @@ class Helper
foreach ($licenses as $license){
$avail = $license->remaincount();
if ($avail <= ($license->min_amt) + $alert_threshold) {
if ($avail < ($license->min_amt) + $alert_threshold) {
if ($avail > 0) {
$percent = number_format((($avail / $license->min_amt) * 100), 0);
} else {
@@ -1386,19 +1384,7 @@ class Helper
* @return string[]
*/
public static function SettingUrls(){
$settings=[
'#',
'fields*',
'statuslabels*',
'models*',
'categories*',
'manufacturers*',
'suppliers*',
'departments*',
'locations*',
'companies*',
'depreciations*'
];
$settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index'];
return $settings;
}
@@ -1584,6 +1570,7 @@ class Helper
]) ? 'rtl' : 'ltr';
}
static public function getRedirectOption($request, $id, $table, $item_id = null) : RedirectResponse
{
@@ -1748,83 +1735,4 @@ class Helper
}
return $mismatched;
}
static public function labelFieldLayoutScaling(
$pdf,
iterable|\Closure $fields,
float $currentX,
float $usableWidth,
float $usableHeight,
float $baseLabelSize,
float $baseFieldSize,
float $baseFieldMargin,
?string $title = null,
float $baseTitleSize = 0.0,
float $baseTitleMargin = 0.0,
float $baseLabelPadding = 1.5,
float $baseGap = 1.5,
float $maxScale = 1.8,
string $labelFont = 'freesans',
) : array
{
$fieldCount = count($fields);
$perFieldHeight = max($baseLabelSize, $baseFieldSize) + $baseFieldMargin;
$baseFieldsHeight = $fieldCount * $perFieldHeight;
$hasTitle = is_string($title) && trim($title) !== '';
$baseTitleHeight = $hasTitle ? ($baseTitleSize + $baseTitleMargin) : 0.0;
$baseTotalHeight = $baseTitleHeight + $baseFieldsHeight;
$scale = 1.0;
if ($baseTotalHeight > 0 && $usableHeight > 0) {
$scale = $usableHeight / $baseTotalHeight;
}
$scale = min($scale, $maxScale);
$labelSize = $baseLabelSize;
$fieldSize = $baseFieldSize * $scale;
$fieldMargin = $baseFieldMargin * $scale;
$rowAdvance = max($labelSize, $fieldSize) + $fieldMargin;
$titleSize = $hasTitle ? ($baseTitleSize * $scale) : 0.0;
$titleMargin = $hasTitle ? ($baseTitleMargin * $scale) : 0.0;
$titleAdvance = $hasTitle ? ($titleSize + $titleMargin) : 0.0;
$pdf->SetFont($labelFont, '', $baseLabelSize);
$maxLabelWidthPerUnit = 0;
foreach ($fields as $field) {
$rawLabel = $field['label'] ?? null;
// If no label, do not include it in label-column sizing
if (!is_string($rawLabel) || trim($rawLabel) === '') {
continue;
}
$label = rtrim($field['label'], ':') . ':';
$width = $pdf->GetStringWidth($label);
$maxLabelWidthPerUnit = max($maxLabelWidthPerUnit, $width / $baseLabelSize);
}
$labelPadding = $baseLabelPadding * $scale;
$gap = $baseGap * $scale;
$labelWidth = ($maxLabelWidthPerUnit * $labelSize) + $labelPadding;
$valueX = $currentX + $labelWidth + $gap;
$valueWidth = $usableWidth - $labelWidth - $gap;
return compact(
'scale',
'hasTitle',
'titleSize',
'titleMargin',
'titleAdvance',
'labelSize',
'fieldSize',
'fieldMargin',
'rowAdvance',
'labelWidth',
'valueX',
'valueWidth'
);
}
}
+1 -54
View File
@@ -46,8 +46,6 @@ class IconHelper
return 'fa-regular fa-envelope';
case 'phone':
return 'fa-solid fa-phone';
case 'fax':
return 'fa-solid fa-fax';
case 'mobile':
return 'fas fa-mobile-screen-button';
case 'long-arrow-right':
@@ -55,7 +53,7 @@ class IconHelper
case 'download':
return 'fas fa-download';
case 'checkmark':
return 'fas fa-check';
return 'fas fa-check icon-white';
case 'x':
return 'fas fa-times';
case 'logout':
@@ -131,12 +129,9 @@ class IconHelper
return 'fa-regular fa-clipboard';
case 'paperclip':
return 'fas fa-paperclip';
case 'contact-card':
return 'fa-regular fa-id-card';
case 'files':
return 'fa-regular fa-file';
case 'more-info':
case 'support':
return 'far fa-life-ring';
case 'calendar':
return 'fas fa-calendar';
@@ -206,54 +201,6 @@ class IconHelper
return 'fa-solid fa-lightbulb';
case 'highlight':
return 'fa-solid fa-highlighter';
case 'manager':
return 'fa-solid fa-building-user';
case 'company':
return 'fa-regular fa-building';
case 'parent':
return 'fa-solid fa-building-flag';
case 'number':
return 'fa-solid fa-hashtag';
case 'depreciation':
return 'fa-solid fa-arrows-down-to-line';
case 'depreciation-calendar':
case 'expiration':
case 'terminates':
return 'fa-regular fa-calendar-xmark';
case 'manufacturer':
return 'fa-solid fa-industry';
case 'fieldset' :
return 'fa-regular fa-rectangle-list';
case 'deleted-date':
return 'fa-solid fa-calendar-xmark';
case 'eol':
return 'fa-regular fa-calendar-days';
case 'category':
return 'fa-solid fa-icons';
case 'cost':
return 'fa-solid fa-money-bills';
case 'available':
return 'fa-solid fa-box';
case 'checkedout':
return 'fa-solid fa-box-open';
case 'purchase_order':
return 'fa-solid fa-file-invoice-dollar';
case 'order':
return 'fa-solid fa-file-invoice';
case 'checkout-all':
return 'fa-solid fa-arrows-down-to-people';
case 'square-right':
return 'fa-regular fa-square-caret-right';
case 'square-left':
return 'fa-regular fa-square-caret-left';
case 'square':
return 'fa-solid fa-square';
case 'models':
case 'model':
return 'fa-solid fa-boxes-stacked';
case 'min-qty':
return 'fa-solid fa-chart-pie';
}
}
}
@@ -90,10 +90,10 @@ class AccessoriesController extends Controller
$accessory = $request->handleImages($accessory);
}
if($request->input('redirect_option') === 'back'){
if($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
// Was the accessory created?
@@ -182,11 +182,7 @@ class AccessoriesController extends Controller
$accessory = $request->handleImages($accessory);
if($request->input('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
}
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($accessory->save()) {
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
@@ -76,7 +76,7 @@ class AccessoryCheckinController extends Controller
if ($accessory_checkout->delete()) {
event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at));
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
return Helper::getRedirectOption($request, $accessory->id, 'Accessories')
->with('success', trans('admin/accessories/message.checkin.success'));
@@ -67,7 +67,7 @@ class AccessoryCheckoutController extends Controller
*/
public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse
{
$this->authorize('checkout', $accessory);
$target = $this->determineCheckoutTarget();
@@ -89,19 +89,12 @@ class AccessoryCheckoutController extends Controller
$accessory_checkout->save();
}
event(new CheckoutableCheckedOut(
$accessory,
$target,
auth()->user(),
$request->input('note'),
[],
$accessory->checkout_qty,
));
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
$request->request->add(['assigned_to' => $target->id]);
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => $request->input('checkout_to_type')]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
// Redirect to the new accessory page
@@ -13,9 +13,9 @@ use App\Models\Company;
use App\Models\Contracts\Acceptable;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\AcceptanceItemAcceptedNotification;
use App\Notifications\AcceptanceItemAcceptedToUserNotification;
use App\Notifications\AcceptanceItemDeclinedNotification;
use App\Notifications\AcceptanceAssetAcceptedNotification;
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
use App\Notifications\AcceptanceAssetDeclinedNotification;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
@@ -138,14 +138,14 @@ class AcceptanceController extends Controller
// Convert PDF logo to base64 for TCPDF
// This is needed for TCPDF to properly embed the image if it's a png and the cache isn't writable
$encoded_logo = null;
if (($settings->acceptance_pdf_logo) && (Storage::disk('public')->exists($settings->acceptance_pdf_logo))) {
if ($settings->acceptance_pdf_logo) {
$encoded_logo = base64_encode(file_get_contents(public_path() . '/uploads/' . $settings->acceptance_pdf_logo));
}
// Get the data array ready for the notifications and PDF generation
$data = [
'item_tag' => $item->asset_tag,
'item_name' => $item->display_name, // this handles licenses seats, which don't have a 'name' field
'item_name' => $item->name, // this handles licenses seats, which don't have a 'name' field
'item_model' => $item->model?->name,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
@@ -183,13 +183,13 @@ class AcceptanceController extends Controller
// Add the attachment for the signing user into the $data array
$data['file'] = $pdf_filename;
try {
$assigned_user->notify((new AcceptanceItemAcceptedToUserNotification($data))->locale($assigned_user->locale));
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale));
} catch (\Exception $e) {
Log::warning($e);
}
}
try {
$acceptance->notify((new AcceptanceItemAcceptedNotification($data))->locale(Setting::getSettings()->locale));
$acceptance->notify((new AcceptanceAssetAcceptedNotification($data))->locale(Setting::getSettings()->locale));
} catch (\Exception $e) {
Log::warning($e);
}
@@ -204,7 +204,7 @@ class AcceptanceController extends Controller
$acceptance->decline($sig_filename, $request->input('note'));
}
$acceptance->notify(new AcceptanceItemDeclinedNotification($data));
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
Log::debug('New event acceptance.');
event(new CheckoutDeclined($acceptance));
$return_msg = trans('admin/users/message.declined');
@@ -216,7 +216,7 @@ class AcceptanceController extends Controller
try {
$recipient = User::find($acceptance->alert_on_response_id);
if ($recipient?->email) {
if ($recipient) {
Log::debug('Attempting to send email acceptance.');
Mail::to($recipient)->send(new CheckoutAcceptanceResponseMail(
$acceptance,
@@ -325,14 +325,7 @@ class AccessoriesController extends Controller
}
// Set this value to be able to pass the qty through to the event
event(new CheckoutableCheckedOut(
$accessory,
$target,
auth()->user(),
$request->input('note'),
[],
$accessory->checkout_qty,
));
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkout.success')));
@@ -396,7 +389,7 @@ class AccessoriesController extends Controller
]);
if ($request->filled('search')) {
$accessories = $accessories->where('accessories.name', 'LIKE', '%'.$request->input('search').'%');
$accessories = $accessories->where('accessories.name', 'LIKE', '%'.$request->get('search').'%');
}
$accessories = $accessories->orderBy('name', 'ASC')->paginate(50);
@@ -249,7 +249,7 @@ class AssetModelsController extends Controller
* it, but I'll be damned if I can think of one. - snipe
*/
if ($request->filled('custom_fieldset_id')) {
$assetmodel->fieldset_id = $request->input('custom_fieldset_id');
$assetmodel->fieldset_id = $request->get('custom_fieldset_id');
}
+30 -44
View File
@@ -3,39 +3,37 @@
namespace App\Http\Controllers\Api;
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckoutRequest;
use App\Http\Requests\FilterRequest;
use App\Http\Requests\StoreAssetRequest;
use App\Http\Requests\UpdateAssetRequest;
use App\Http\Traits\MigratesLegacyAssetLocations;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\ComponentsTransformer;
use App\Models\AccessoryCheckout;
use App\Models\CheckoutAcceptance;
use App\Models\LicenseSeat;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Gate;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckoutRequest;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\AccessoryCheckout;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\CustomField;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\Setting;
use App\Models\User;
use App\View\Label;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use App\View\Label;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
@@ -58,7 +56,7 @@ class AssetsController extends Controller
* @param int $assetId
* @since [v4.0]
*/
public function index(FilterRequest $request, $action = null, $upcoming_status = null) : JsonResponse | array
public function index(Request $request, $action = null, $upcoming_status = null) : JsonResponse | array
{
@@ -154,15 +152,6 @@ class AssetsController extends Controller
}
$assets = Asset::select('assets.*')
->addSelect([
'first_checkout_at' => Actionlog::query()
->select('created_at')
->whereColumn('item_id', 'assets.id')
->where('item_type', Asset::class)
->where('action_type', 'checkout')
->orderBy('created_at')
->limit(1),
])
->with(
'model',
'location',
@@ -387,7 +376,7 @@ class AssetsController extends Controller
}
if ($request->filled('order_number')) {
$assets->where('assets.order_number', '=', strval($request->input('order_number')));
$assets->where('assets.order_number', '=', strval($request->get('order_number')));
}
// This is kinda gross, but we need to do this because the Bootstrap Tables
@@ -664,7 +653,7 @@ class AssetsController extends Controller
public function store(StoreAssetRequest $request): JsonResponse
{
$asset = new Asset();
$asset->model()->associate(AssetModel::find((int) $request->input('model_id')));
$asset->model()->associate(AssetModel::find((int) $request->get('model_id')));
$asset->fill($request->validated());
$asset->created_by = auth()->id();
@@ -693,8 +682,8 @@ class AssetsController extends Controller
// If input value is null, use custom field's default value
if ($field_val == null) {
Log::debug('Field value for ' . $field->db_column . ' is null');
$field_val = $field->defaultValue($request->input('model_id'));
Log::debug('Use the default fieldset value of ' . $field->defaultValue($request->input('model_id')));
$field_val = $field->defaultValue($request->get('model_id'));
Log::debug('Use the default fieldset value of ' . $field->defaultValue($request->get('model_id')));
}
// if the field is set to encrypted, make sure we encrypt the value
@@ -705,7 +694,7 @@ class AssetsController extends Controller
// If input value is null, use custom field's default value
if (($field_val == null) && ($request->has('model_id') != '')) {
$field_val = Crypt::encrypt($field->defaultValue($request->input('model_id')));
$field_val = Crypt::encrypt($field->defaultValue($request->get('model_id')));
} else {
$field_val = Crypt::encrypt($request->input($field->db_column));
}
@@ -723,15 +712,15 @@ class AssetsController extends Controller
}
if ($asset->save()) {
if ($request->input('assigned_user')) {
if ($request->get('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif ($request->input('assigned_asset')) {
} elseif ($request->get('assigned_asset')) {
$target = Asset::find(request('assigned_asset'));
} elseif ($request->input('assigned_location')) {
} elseif ($request->get('assigned_location')) {
$target = Location::find(request('assigned_location'));
}
if (isset($target)) {
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->input('name')));
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')));
}
if ($asset->image) {
@@ -808,22 +797,19 @@ class AssetsController extends Controller
}
}
if ($asset->save()) {
if (($request->filled('assigned_user')) && ($target = User::find($request->input('assigned_user')))) {
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
$location = $target->location_id;
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->input('assigned_asset')))) {
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) {
$location = $target->location_id;
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $asset->id)
->update(['location_id' => $target->location_id]);
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->input('assigned_location')))) {
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
$location = $target->id;
}
if (isset($target)) {
// Using `->has` preserves the asset name if the name parameter was not included in request.
$asset_name = request()->has('name') ? request('name') : $asset->name;
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', $asset_name, $location);
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
}
if ($asset->image) {
@@ -967,7 +953,7 @@ class AssetsController extends Controller
}
if ($request->filled('status_id')) {
$asset->status_id = $request->input('status_id');
$asset->status_id = $request->get('status_id');
}
if (! isset($target)) {
@@ -1047,7 +1033,7 @@ class AssetsController extends Controller
$checkin_at = $request->filled('checkin_at') ? $request->input('checkin_at') . ' ' . date('H:i:s') : date('Y-m-d H:i:s');
$originalValues = $asset->getRawOriginal();
if (($request->filled('checkin_at')) && ($request->input('checkin_at') != date('Y-m-d'))) {
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
$originalValues['action_date'] = $checkin_at;
}
@@ -1156,7 +1142,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->input('model_id'));
* $model = AssetModel::find($request->get('model_id'));
*/
if (($asset->model) && ($asset->model->fieldset)) {
$payload['custom_fields'] = [];
@@ -43,7 +43,6 @@ class CategoriesController extends Controller
'created_at',
'updated_at',
'image',
'tag_color',
'notes',
];
@@ -58,7 +57,6 @@ class CategoriesController extends Controller
'require_acceptance',
'checkin_email',
'image',
'tag_color',
'notes',
])
->with('adminuser')
@@ -265,7 +263,7 @@ class CategoriesController extends Controller
]);
if ($request->filled('search')) {
$categories = $categories->where('name', 'LIKE', '%'.$request->input('search').'%');
$categories = $categories->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$categories = $categories->where('category_type', $category_type)->orderBy('name', 'ASC')->paginate(50);
@@ -38,7 +38,6 @@ class CompaniesController extends Controller
'accessories_count',
'consumables_count',
'components_count',
'tag_color',
'notes',
];
@@ -65,11 +64,6 @@ class CompaniesController extends Controller
$companies->where('created_by', '=', $request->input('created_by'));
}
if ($request->filled('tag_color')) {
$companies->where('tag_color', '=', $request->input('tag_color'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $companies->count()) ? $companies->count() : app('api_offset_value');
@@ -197,12 +191,11 @@ class CompaniesController extends Controller
'companies.name',
'companies.email',
'companies.image',
'companies.tag_color',
]);
if ($request->filled('search')) {
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->input('search').'%');
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->get('search').'%');
}
$companies = $companies->orderBy('name', 'ASC')->paginate(50);
@@ -58,8 +58,8 @@ class ComponentsController extends Controller
];
$components = Component::select('components.*')
->with('company', 'location', 'category', 'supplier', 'adminuser', 'manufacturer')
->withSum('unconstrainedAssets as sum_unconstrained_assets', 'components_assets.assigned_qty');
->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets')
->withSum('uncontrainedAssets', 'components_assets.assigned_qty');
$filter = [];
@@ -112,8 +112,7 @@ class ComponentsController extends Controller
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$components_count = $components->count();
$offset = ($request->input('offset') > $components_count) ? $components_count : app('api_offset_value');
$offset = ($request->input('offset') > $components->count()) ? $components->count() : app('api_offset_value');
$limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -144,7 +143,7 @@ class ComponentsController extends Controller
break;
}
$total = $components_count;
$total = $components->count();
$components = $components->skip($offset)->take($limit)->get();
return (new ComponentsTransformer)->transformComponents($components, $total);
@@ -303,11 +302,11 @@ class ComponentsController extends Controller
}
// Make sure there is at least one available to checkout
if ($component->numRemaining() < $request->input('assigned_qty')) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->input('assigned_qty')])));
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->input('assigned_qty')) {
if ($component->numRemaining() >= $request->get('assigned_qty')) {
$asset = Asset::find($request->input('assigned_to'));
$component->assigned_to = $request->input('assigned_to');
@@ -315,18 +314,18 @@ class ComponentsController extends Controller
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'created_at' => Carbon::now(),
'assigned_qty' => $request->input('assigned_qty', 1),
'assigned_qty' => $request->get('assigned_qty', 1),
'created_by' => auth()->id(),
'asset_id' => $request->input('assigned_to'),
'note' => $request->input('note'),
'asset_id' => $request->get('assigned_to'),
'note' => $request->get('note'),
]);
$component->logCheckout($request->input('note'), $asset, null, [], $request->get('assigned_qty', 1));
$component->logCheckout($request->input('note'), $asset);
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->input('assigned_qty')])));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->get('assigned_qty')])));
}
/**
@@ -326,14 +326,8 @@ class ConsumablesController extends Controller
);
}
event(new CheckoutableCheckedOut(
$consumable,
$user,
auth()->user(),
$request->input('note'),
[],
$consumable->checkout_qty,
));
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
@@ -352,7 +346,7 @@ class ConsumablesController extends Controller
]);
if ($request->filled('search')) {
$consumables = $consumables->where('consumables.name', 'LIKE', '%'.$request->input('search').'%');
$consumables = $consumables->where('consumables.name', 'LIKE', '%'.$request->get('search').'%');
}
$consumables = $consumables->orderBy('name', 'ASC')->paginate(50);
@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreDepartmentRequest;
use App\Http\Transformers\DepartmentsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\Department;
@@ -24,23 +23,21 @@ class DepartmentsController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', Department::class);
$allowed_columns = ['id', 'name', 'image', 'users_count', 'notes', 'tag_color'];
$allowed_columns = ['id', 'name', 'image', 'users_count', 'notes'];
$departments = Department::select(
[
'departments.id',
'departments.name',
'departments.phone',
'departments.fax',
'departments.location_id',
'departments.company_id',
'departments.manager_id',
'departments.created_at',
'departments.updated_at',
'departments.image',
'departments.tag_color',
'departments.notes'
])->with('location')->with('manager')->with('company')->withCount('users as users_count');
'departments.id',
'departments.name',
'departments.phone',
'departments.fax',
'departments.location_id',
'departments.company_id',
'departments.manager_id',
'departments.created_at',
'departments.updated_at',
'departments.image',
'departments.notes',
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
if ($request->filled('search')) {
$departments = $departments->TextSearch($request->input('search'));
@@ -62,10 +59,6 @@ class DepartmentsController extends Controller
$departments->where('location_id', '=', $request->input('location_id'));
}
if ($request->filled('tag_color')) {
$departments->where('tag_color', '=', $request->input('departments.tag_color'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $departments->count()) ? $departments->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -101,17 +94,18 @@ class DepartmentsController extends Controller
* @since [v4.0]
* @param \App\Http\Requests\ImageUploadRequest $request
*/
public function store(StoreDepartmentRequest $request): JsonResponse
public function store(ImageUploadRequest $request) : JsonResponse
{
$this->authorize('create', Department::class);
$department = new Department;
$department->fill($request->validated());
$department->fill($request->all());
$department = $request->handleImages($department);
$department->created_by = auth()->id();
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
if ($department->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new DepartmentsTransformer)->transformDepartment($department), trans('admin/departments/message.create.success')));
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
@@ -127,7 +121,7 @@ class DepartmentsController extends Controller
public function show($id) : array
{
$this->authorize('view', Department::class);
$department = Department::withCount('users as users_count')->findOrFail($id);
$department = Department::findOrFail($id);
return (new DepartmentsTransformer)->transformDepartment($department);
}
@@ -147,7 +141,7 @@ class DepartmentsController extends Controller
$department = $request->handleImages($department);
if ($department->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new DepartmentsTransformer)->transformDepartment($department), trans('admin/departments/message.update.success')));
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.update.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
@@ -191,11 +185,10 @@ class DepartmentsController extends Controller
'id',
'name',
'image',
'tag_color',
]);
if ($request->filled('search')) {
$departments = $departments->where('name', 'LIKE', '%'.$request->input('search').'%');
$departments = $departments->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$departments = $departments->orderBy('name', 'ASC')->paginate(50);
@@ -24,7 +24,7 @@ class GroupsController extends Controller
$this->authorize('view', Group::class);
$groups = Group::select(['id', 'name', 'permissions', 'notes', 'created_at', 'updated_at', 'created_by'])->with('adminuser')->withCount('users as users_count');
$groups = Group::select('id', 'name', 'permissions', 'notes', 'created_at', 'updated_at', 'created_by')->with('adminuser')->withCount('users as users_count');
if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search'));
@@ -50,7 +50,6 @@ class GroupsController extends Controller
'id',
'name',
'created_at',
'updated_at',
'users_count',
];
+5 -32
View File
@@ -15,7 +15,6 @@ use Illuminate\Database\Eloquent\JsonEncodingException;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use League\Csv\Reader;
use Onnov\DetectEncoding\EncodingDetector;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
@@ -150,9 +149,7 @@ class ImportController extends Controller
}
$date = date('Y-m-d-his');
$fixed_filename = Str::of($file->getClientOriginalName())->basename('.csv').'.csv';
$fixed_filename = str_slug($file->getClientOriginalName());
try {
$file->move($path, $date.'-'.$fixed_filename);
} catch (FileException $exception) {
@@ -196,7 +193,7 @@ class ImportController extends Controller
$this->authorize('import');
// Run a backup immediately before processing
if ($request->input('run-backup')) {
if ($request->get('run-backup')) {
Log::debug('Backup manually requested via importer');
Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H-i-s')]);
} else {
@@ -212,49 +209,38 @@ class ImportController extends Controller
$errors = $request->import($import);
$redirectTo = 'hardware.index';
switch ($request->input('import-type')) {
switch ($request->get('import-type')) {
case 'asset':
$model_perms = 'App\Models\Asset';
$redirectTo = 'hardware.index';
break;
case 'assetModel':
$model_perms = 'App\Models\AssetModel';
$redirectTo = 'models.index';
break;
case 'accessory':
$model_perms = 'App\Models\Accessory';
$redirectTo = 'accessories.index';
break;
case 'consumable':
$model_perms = 'App\Models\Consumable';
$redirectTo = 'consumables.index';
break;
case 'component':
$model_perms = 'App\Models\Component';
$redirectTo = 'components.index';
break;
case 'license':
$model_perms = 'App\Models\License';
$redirectTo = 'licenses.index';
break;
case 'user':
$model_perms = 'App\Models\User';
$redirectTo = 'users.index';
break;
case 'location':
$model_perms = 'App\Models\Location';
$redirectTo = 'locations.index';
break;
case 'supplier':
$model_perms = 'App\Models\Supplier';
$redirectTo = 'suppliers.index';
break;
case 'manufacturer':
$model_perms = 'App\Models\Manufacturer';
$redirectTo = 'manufacturers.index';
break;
case 'category':
$model_perms = 'App\Models\Category';
$redirectTo = 'categories.index';
break;
}
@@ -265,11 +251,7 @@ class ImportController extends Controller
//Flash message before the redirect
Session::flash('success', trans('admin/hardware/message.import.success'));
if (auth()->user()->can('view', $model_perms)) {
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
}
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route('imports.index')]));
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
}
/**
@@ -279,16 +261,9 @@ class ImportController extends Controller
*/
public function destroy($import_id) : JsonResponse
{
$this->authorize('import');
$this->authorize('create', Asset::class);
if ($import = Import::find($import_id)) {
if ((auth()->user()->id != $import->created_by) && (!auth()->user()->isSuperUser())) {
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
}
try {
// Try to delete the file
Storage::delete('imports/'.$import->file_path);
@@ -305,6 +280,4 @@ class ImportController extends Controller
}
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
}
}
@@ -24,7 +24,7 @@ class LabelsController extends Controller
$labels = Label::find();
if ($request->filled('search')) {
$search = $request->input('search');
$search = $request->get('search');
$labels = $labels->filter(function ($label, $index) use ($search) {
return stripos($label->getName(), $search) !== false;
});
@@ -32,11 +32,11 @@ class LabelsController extends Controller
$total = $labels->count();
$offset = $request->input('offset', 0);
$offset = $request->get('offset', 0);
$offset = ($offset > $total) ? $total : $offset;
$maxLimit = config('app.max_results');
$limit = $request->input('limit', $maxLimit);
$limit = $request->get('limit', $maxLimit);
$limit = ($limit > $maxLimit) ? $maxLimit : $limit;
$labels = $labels->skip($offset)->take($limit);
@@ -26,11 +26,11 @@ class LicenseSeatsController extends Controller
if ($license = License::find($licenseId)) {
$this->authorize('view', $license);
$seats = LicenseSeat::with('license', 'user', 'asset', 'user.department', 'user.company', 'asset.company')
$seats = LicenseSeat::with('license', 'user', 'asset', 'user.department')
->where('license_seats.license_id', $licenseId);
if ($request->input('status') == 'available') {
$seats->whereNull('license_seats.assigned_to')->whereNull('license_seats.asset_id');
$seats->whereNull('license_seats.assigned_to');
}
if ($request->input('status') == 'assigned') {
@@ -40,10 +40,8 @@ class LicenseSeatsController extends Controller
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
if ($request->input('sort') == 'assigned_user.department') {
if ($request->input('sort') == 'department') {
$seats->OrderDepartments($order);
} elseif ($request->input('sort') == 'assigned_user.company') {
$seats->OrderCompany($order);
} else {
$seats->orderBy('updated_at', $order);
}
@@ -79,14 +77,17 @@ class LicenseSeatsController extends Controller
{
$this->authorize('view', License::class);
if ($licenseSeat = LicenseSeat::where('license_id', $licenseId)->find($seatId)) {
return (new LicenseSeatsTransformer)->transformLicenseSeat($licenseSeat);
// sanity checks:
// 1. does the license seat exist?
if (! $licenseSeat = LicenseSeat::find($seatId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat not found'));
}
// 2. does the seat belong to the specified license?
if (! $license = $licenseSeat->license()->first() || $license->id != intval($licenseId)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat does not belong to the specified license'));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Seat ID or license not found or the seat does not belong to this license'));
return (new LicenseSeatsTransformer)->transformLicenseSeat($licenseSeat);
}
/**
@@ -119,22 +120,17 @@ class LicenseSeatsController extends Controller
// check if this update is a checkin operation
// 1. are relevant fields touched at all?
$assignmentTouched = $licenseSeat->isDirty('assigned_to') || $licenseSeat->isDirty('asset_id');
$anythingTouched = $licenseSeat->isDirty();
$touched = $licenseSeat->isDirty('assigned_to') || $licenseSeat->isDirty('asset_id');
// 2. are they cleared? if yes then this is a checkin operation
$is_checkin = ($touched && $licenseSeat->assigned_to === null && $licenseSeat->asset_id === null);
if (! $anythingTouched) {
return response()->json(
Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success'))
);
if (! $touched) {
// nothing to update
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
if( $assignmentTouched && $licenseSeat->unreassignable_seat) {
if( $touched && $licenseSeat->unreassignable_seat) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.unavailable')));
}
// 2. are they cleared? if yes then this is a checkin operation
$is_checkin = ($assignmentTouched && $licenseSeat->assigned_to === null && $licenseSeat->asset_id === null);
$target = null;
// the logging functions expect only one "target". if both asset and user are present in the request,
// we simply let assets take precedence over users...
if ($licenseSeat->isDirty('assigned_to')) {
@@ -144,23 +140,25 @@ class LicenseSeatsController extends Controller
$target = $is_checkin ? $oldAsset : Asset::find($licenseSeat->asset_id);
}
if ($assignmentTouched && is_null($target)){
if (is_null($target)){
return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
}
if ($licenseSeat->save()) {
if($assignmentTouched) {
if ($is_checkin) {
if (!$licenseSeat->license->reassignable) {
$licenseSeat->unreassignable_seat = true;
$licenseSeat->save();
}
$licenseSeat->logCheckin($target, $licenseSeat->notes);
} else {
// in this case, relevant fields are touched but it's not a checkin operation. so it must be a checkout operation.
$licenseSeat->logCheckout($request->input('notes'), $target);
if ($is_checkin) {
if(!$licenseSeat->license->reassignable){
$licenseSeat->unreassignable_seat = true;
$licenseSeat->save();
}
$licenseSeat->logCheckin($target, $licenseSeat->notes);
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
// in this case, relevant fields are touched but it's not a checkin operation. so it must be a checkout operation.
$licenseSeat->logCheckout($request->input('notes'), $target);
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
@@ -265,7 +265,7 @@ class LicensesController extends Controller
]);
if ($request->filled('search')) {
$licenses = $licenses->where('licenses.name', 'LIKE', '%'.$request->input('search').'%');
$licenses = $licenses->where('licenses.name', 'LIKE', '%'.$request->get('search').'%');
}
$licenses = $licenses->orderBy('name', 'ASC')->paginate(50);
@@ -59,7 +59,6 @@ class LocationsController extends Controller
'state',
'updated_at',
'zip',
'tag_color',
'notes',
];
@@ -82,8 +81,6 @@ class LocationsController extends Controller
'locations.ldap_ou',
'locations.currency',
'locations.company_id',
'locations.tag_color',
'locations.tag_color',
'locations.notes',
'locations.created_by',
'locations.deleted_at',
@@ -148,10 +145,6 @@ class LocationsController extends Controller
$locations->onlyTrashed();
}
if ($request->filled('tag_color')) {
$locations->where('tag_color', '=', $request->input('locations.tag_color'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -200,7 +193,7 @@ class LocationsController extends Controller
// Only scope location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$location->company_id = Company::getIdForCurrentUser($request->get('company_id'));
// check if parent is set and has a different company
if ($location->parent_id && Location::find($location->parent_id)->company_id != $location->company_id) {
response()->json(Helper::formatStandardApiResponse('error', null, 'different company than parent'));
@@ -242,7 +235,6 @@ class LocationsController extends Controller
'locations.currency',
'locations.company_id',
'locations.notes',
'locations.tag_color',
])
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
@@ -278,13 +270,13 @@ class LocationsController extends Controller
if ($request->filled('company_id')) {
// Only scope location if the setting is enabled
if (Setting::getSettings()->scope_locations_fmcs) {
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$location->company_id = Company::getIdForCurrentUser($request->get('company_id'));
// check if there are related objects with different company
if (Helper::test_locations_fmcs(false, $id, $location->company_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'error scoped locations'));
}
} else {
$location->company_id = $request->input('company_id');
$location->company_id = $request->get('company_id');
}
}
@@ -410,7 +402,6 @@ class LocationsController extends Controller
'locations.name',
'locations.parent_id',
'locations.image',
'locations.tag_color',
]);
// Only scope locations if the setting is enabled
@@ -47,7 +47,6 @@ class ManufacturersController extends Controller
'consumables_count',
'components_count',
'licenses_count',
'tag_color',
'notes',
];
@@ -64,7 +63,6 @@ class ManufacturersController extends Controller
'updated_at',
'image',
'deleted_at',
'tag_color',
'notes',
])
->with('adminuser')
@@ -78,16 +76,10 @@ class ManufacturersController extends Controller
$manufacturers->onlyTrashed();
}
if ($request->input('status') == 'deleted') {
$manufacturers->onlyTrashed();
}
if ($request->filled('search')) {
$manufacturers = $manufacturers->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$manufacturers->where('name', '=', $request->input('name'));
}
@@ -112,10 +104,6 @@ class ManufacturersController extends Controller
$manufacturers->where('support_email', '=', $request->input('support_email'));
}
if ($request->filled('tag_color')) {
$manufacturers->where('tag_color', '=', $request->input('manufacturers.tag_color'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -270,11 +258,10 @@ class ManufacturersController extends Controller
'id',
'name',
'image',
'tag_color',
]);
if ($request->filled('search')) {
$manufacturers = $manufacturers->where('name', 'LIKE', '%'.$request->input('search').'%');
$manufacturers = $manufacturers->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$manufacturers = $manufacturers->orderBy('name', 'ASC')->paginate(50);
@@ -145,7 +145,7 @@ class PredefinedKitsController extends Controller
]);
if ($request->filled('search')) {
$kits = $kits->where('name', 'LIKE', '%'.$request->input('search').'%');
$kits = $kits->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$kits = $kits->orderBy('name', 'ASC')->paginate(50);
@@ -184,7 +184,7 @@ class PredefinedKitsController extends Controller
$quantity = 1;
}
$license_id = $request->input('license');
$license_id = $request->get('license');
$relation = $kit->licenses();
if ($relation->find($license_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['license' => trans('admin/kits/general.license_error')]));
@@ -254,7 +254,7 @@ class PredefinedKitsController extends Controller
$kit = PredefinedKit::findOrFail($kit_id);
$model_id = $request->input('model');
$model_id = $request->get('model');
$quantity = $request->input('quantity', 1);
if ($quantity < 1) {
$quantity = 1;
@@ -332,7 +332,7 @@ class PredefinedKitsController extends Controller
$quantity = 1;
}
$consumable_id = $request->input('consumable');
$consumable_id = $request->get('consumable');
$relation = $kit->consumables();
if ($relation->find($consumable_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['consumable' => trans('admin/kits/general.consumable_error')]));
@@ -406,7 +406,7 @@ class PredefinedKitsController extends Controller
$quantity = 1;
}
$accessory_id = $request->input('accessory');
$accessory_id = $request->get('accessory');
$relation = $kit->accessories();
if ($relation->find($accessory_id)) {
return response()->json(Helper::formatStandardApiResponse('error', null, ['accessory' => trans('admin/kits/general.accessory_error')]));
+7 -19
View File
@@ -6,7 +6,6 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\ProfileTransformer;
use App\Models\CheckoutRequest;
use App\Models\Setting;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
use Illuminate\Http\Request;
@@ -15,7 +14,6 @@ use Laravel\Passport\TokenRepository;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Support\Facades\Gate;
use App\Models\CustomField;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -181,24 +179,14 @@ class ProfileController extends Controller
*@since [v8.1.16]
* @author [Godfrey Martinez] [<gmartinez@grokability.com>]
*/
public function eulas(ProfileTransformer $transformer, Request $request)
public function eulas(ProfileTransformer $transformer)
{
if (($request->filled('user_id')) && ($request->input( 'user_id') != 0)) {
$eula_user = User::find($request->input('user_id'));
if (($eula_user) && (Setting::getSettings()->manager_view_enabled) && (auth()->user()->isManagerOf($eula_user))) {
$eulas = $eula_user->eulas;
} else {
return response()->json(Helper:: formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')));
}
} else {
$eulas = auth()->user()->eulas;
}
return response()->json($transformer->transformFiles($eulas, $eulas->count()));
// Only return this user's EULAs
$eulas = auth()->user()->eulas;
return response()->json(
$transformer->transformFiles($eulas, $eulas->count())
);
}
}
@@ -226,7 +226,7 @@ class SettingsController extends Controller
$login_attempts = DB::table('login_attempts');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'created_at';
$total = $login_attempts->count();
$login_attempts->orderBy($sort, $order);
@@ -324,7 +324,7 @@ class StatuslabelsController extends Controller
$statuslabels = Statuslabel::orderBy('default_label', 'desc')->orderBy('name', 'asc')->orderBy('deployable', 'desc');
if ($request->filled('search')) {
$statuslabels = $statuslabels->where('name', 'LIKE', '%'.$request->input('search').'%');
$statuslabels = $statuslabels->where('name', 'LIKE', '%'.$request->get('search').'%');
}
if ($request->filled('deployable')) {
@@ -50,13 +50,12 @@ class SuppliersController extends Controller
'accessories_count',
'components_count',
'consumables_count',
'tag_color',
'url',
'notes',
];
$suppliers = Supplier::select(
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'created_by', 'updated_at', 'deleted_at', 'image', 'notes', 'url', 'zip', 'tag_color'])
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'created_by', 'updated_at', 'deleted_at', 'image', 'notes', 'url', 'zip'])
->withCount('assets as assets_count')
->withCount('licenses as licenses_count')
->withCount('accessories as accessories_count')
@@ -252,11 +251,10 @@ class SuppliersController extends Controller
'id',
'name',
'image',
'tag_color',
]);
if ($request->filled('search')) {
$suppliers = $suppliers->where('suppliers.name', 'LIKE', '%'.$request->input('search').'%');
$suppliers = $suppliers->where('suppliers.name', 'LIKE', '%'.$request->get('search').'%');
}
$suppliers = $suppliers->orderBy('name', 'ASC')->paginate(50);
@@ -110,18 +110,15 @@ class UploadedFilesController extends Controller
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile(self::$map_storage_path[$object_type], self::$map_file_prefix[$object_type].'-'.$object->id, $file);
$files[] = $file_name;
$object->logUpload($file_name, $request->input('notes'));
$object->logUpload($file_name, $request->get('notes'));
}
if (isset($files)) {
$file_results = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
->where('item_type', '=', self::$map_object_type[$object_type])
->where('item_id', '=', $id)->whereIn('filename', $files)
->get();
return response()->json(Helper::formatStandardApiResponse('success', (new UploadedFilesTransformer())->transformFiles($file_results, count($file_results)), trans_choice('general.file_upload_status.upload.success', count($files))));
}
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
->where('item_type', '=', self::$map_object_type[$object_type])
->where('item_id', '=', $id)->whereIn('filename', $files)
->get();
return response()->json(Helper::formatStandardApiResponse('success', (new UploadedFilesTransformer())->transformFiles($files, count($files)), trans_choice('general.file_upload_status.upload.success', count($files))));
}
// No files were submitted
+96 -124
View File
@@ -31,7 +31,6 @@ use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;
use App\Http\Requests\DeleteUserRequest;
use Illuminate\Http\JsonResponse;
use App\Http\Requests\FilterRequest;
class UsersController extends Controller
{
@@ -43,7 +42,7 @@ class UsersController extends Controller
*
* @return array
*/
public function index(FilterRequest $request) : array
public function index(Request $request) : array
{
$this->authorize('view', User::class);
@@ -163,11 +162,6 @@ class UsersController extends Controller
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
if (is_null($filter)) {
$filter = [];
}
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
@@ -253,7 +247,7 @@ class UsersController extends Controller
}
if ($request->filled('group_id')) {
$users = $users->ByGroup($request->input('group_id'));
$users = $users->ByGroup($request->get('group_id'));
}
if ($request->filled('department_id')) {
@@ -400,11 +394,11 @@ class UsersController extends Controller
if ($request->filled('search')) {
$users = $users->where(function ($query) use ($request) {
$query->SimpleNameSearch($request->input('search'))
->orWhere('username', 'LIKE', '%'.$request->input('search').'%')
->orWhere('display_name', 'LIKE', '%'.$request->input('search').'%')
->orWhere('email', 'LIKE', '%'.$request->input('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->input('search').'%');
$query->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('display_name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('email', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
});
}
@@ -459,7 +453,7 @@ class UsersController extends Controller
//
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
$user->password = bcrypt($request->get('password'));
} else {
$user->password = $user->noPassword();
}
@@ -478,22 +472,12 @@ class UsersController extends Controller
}
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
$validator = Validator::make($request->only('groups'), [
'groups.*' => 'integer|exists:permission_groups,id',
]);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
}
// Sync the groups since the user is a superuser and the groups pass validation
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync([]);
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.create')));
}
@@ -532,99 +516,93 @@ class UsersController extends Controller
{
$this->authorize('update', User::class);
$this->authorize('update', $user);
$this->authorize('update', $user);
/**
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
* Thanks, jerks. You are why we can't have nice things. - snipe
*
*/
/**
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
* Thanks, jerks. You are why we can't have nice things. - snipe
*
*/
if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
}
// Pull out sensitive fields that require extra permission
$user->fill($request->except(['password', 'username', 'email', 'activated', 'permissions', 'activation_code', 'remember_token', 'two_factor_secret', 'two_factor_enrolled', 'two_factor_optin']));
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
}
if ($request->filled('username')) {
$user->username = $request->input('username');
$user->fill($request->all());
if ($request->filled('company_id')) {
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
}
if ($request->filled('email')) {
$user->email = $request->input('email');
if ($user->id == $request->input('manager_id')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
}
if ($request->filled('activated')) {
$user->activated = $request->input('activated');
}
// check for permissions related fields and pull them out if the current user cannot edit them
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
}
// We need to use has() instead of filled()
// here because we need to overwrite permissions
// if someone needs to null them out
if ($request->filled('display_name')) {
$user->display_name = $request->input('display_name');
}
if ($request->filled('company_id')) {
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
}
if ($user->id == $request->input('manager_id')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
}
if ($request->has('permissions')) {
$permissions_array = $request->input('permissions');
// Strip out the individual superuser permission if the API user isn't a superadmin
if (!auth()->user()->isSuperUser()) {
unset($permissions_array['superuser']);
}
$user->permissions = $permissions_array;
}
if ($request->has('location_id')) {
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
}
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
if ($user->save()) {
// Check if the request has groups passed and has a value, AND that the user us a superuser
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
$validator = Validator::make($request->only('groups'), [
'groups.*' => 'integer|exists:permission_groups,id',
]);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
if ($request->filled('username')) {
$user->username = $request->input('username');
}
if ($request->filled('display_name')) {
$user->display_name = $request->input('display_name');
}
if ($request->filled('email')) {
$user->email = $request->input('email');
}
if ($request->filled('activated')) {
$user->activated = $request->input('activated');
}
// Sync the groups since the user is a superuser and the groups pass validation
$user->groups()->sync($request->input('groups'));
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
// We need to use has() instead of filled()
// here because we need to overwrite permissions
// if someone needs to null them out
if ($request->has('permissions')) {
$permissions_array = $request->input('permissions');
// Strip out the individual superuser permission if the API user isn't a superadmin
if (!auth()->user()->isSuperUser()) {
unset($permissions_array['superuser']);
}
$user->permissions = $permissions_array;
}
if($request->has('location_id')) {
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
}
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
if ($user->save()) {
// Check if the request has groups passed and has a value, AND that the user us a superuser
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
$validator = Validator::make($request->only('groups'), [
'groups.*' => 'integer|exists:permission_groups,id',
]);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
}
// Sync the groups since the user is a superuser and the groups pass validation
$user->groups()->sync($request->input('groups'));
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
}
/**
@@ -642,27 +620,21 @@ class UsersController extends Controller
$this->authorize('delete', $user);
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
if ($user->delete()) {
if ($user->delete()) {
// Remove the user's avatar if they have one
// @todo This should be done on purge, not here
// if (Storage::disk('public')->exists('avatars/' . $user->avatar)) {
// try {
// Storage::disk('public')->delete('avatars/' . $user->avatar);
// } catch (\Exception $e) {
// Log::debug($e);
// }
// }
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
// Remove the user's avatar if they have one
if (Storage::disk('public')->exists('avatars/' . $user->avatar)) {
try {
Storage::disk('public')->delete('avatars/' . $user->avatar);
} catch (\Exception $e) {
Log::debug($e);
}
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.cannot_delete')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
}
@@ -811,7 +783,7 @@ class UsersController extends Controller
if ($request->filled('id')) {
try {
$user = User::find($request->input('id'));
$user = User::find($request->get('id'));
$this->authorize('update', $user);
$user->two_factor_secret = null;
$user->two_factor_enrolled = 0;
@@ -98,10 +98,10 @@ class AssetCheckinController extends Controller
$asset->expected_checkin = null;
$asset->assignedTo()->disassociate($asset);
$asset->accepted = null;
$asset->name = $request->input('name');
$asset->name = $request->get('name');
if ($request->filled('status_id')) {
$asset->status_id = e($request->input('status_id'));
$asset->status_id = e($request->get('status_id'));
}
// Add any custom fields that should be included in the checkout
@@ -112,11 +112,11 @@ class AssetCheckinController extends Controller
$asset->location_id = $asset->rtd_location_id;
if ($request->filled('location_id')) {
Log::debug('NEW Location ID: '.$request->input('location_id'));
$asset->location_id = $request->input('location_id');
Log::debug('NEW Location ID: '.$request->get('location_id'));
$asset->location_id = $request->get('location_id');
if ($request->input('update_default_location') == 0){
$asset->rtd_location_id = $request->input('location_id');
if ($request->get('update_default_location') == 0){
$asset->rtd_location_id = $request->get('location_id');
}
}
@@ -124,9 +124,9 @@ class AssetCheckinController extends Controller
// Handle last checkin date
$checkin_at = date('Y-m-d H:i:s');
if (($request->filled('checkin_at')) && ($request->input('checkin_at') != date('Y-m-d'))) {
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
$originalValues['action_date'] = $checkin_at;
$checkin_at = $request->input('checkin_at');
$checkin_at = $request->get('checkin_at');
}
$asset->last_checkin = $checkin_at;
@@ -145,7 +145,7 @@ class AssetCheckinController extends Controller
$acceptance->delete();
});
session()->put('redirect_option', $request->input('redirect_option'));
session()->put('redirect_option', $request->get('redirect_option'));
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkin');
@@ -88,17 +88,17 @@ class AssetCheckoutController extends Controller
$asset = $this->updateAssetLocation($asset, $target);
$checkout_at = date('Y-m-d H:i:s');
if (($request->filled('checkout_at')) && ($request->input('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->input('checkout_at');
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->get('checkout_at');
}
$expected_checkin = '';
if ($request->filled('expected_checkin')) {
$expected_checkin = $request->input('expected_checkin');
$expected_checkin = $request->get('expected_checkin');
}
if ($request->filled('status_id')) {
$asset->status_id = $request->input('status_id');
$asset->status_id = $request->get('status_id');
}
@@ -123,9 +123,9 @@ class AssetCheckoutController extends Controller
}
}
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => $request->input('checkout_to_type')]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->input('note'), $request->input('name'))) {
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
return Helper::getRedirectOption($request, $asset->id, 'Assets')
->with('success', trans('admin/hardware/message.checkout.success'));
}
+116 -131
View File
@@ -6,7 +6,6 @@ use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\CreateMultipleAssetRequest;
use App\Http\Requests\UpdateAssetRequest;
use App\Models\Actionlog;
use App\Http\Requests\UploadFileRequest;
@@ -99,7 +98,7 @@ class AssetsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
*/
public function store(CreateMultipleAssetRequest $request): RedirectResponse
public function store(ImageUploadRequest $request) : RedirectResponse
{
$this->authorize(Asset::class);
@@ -136,143 +135,129 @@ class AssetsController extends Controller
$successes = [];
$failures = [];
try {
DB::beginTransaction();
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
$asset = new Asset();
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
$asset = new Asset();
$asset->model()->associate($model);
$asset->name = $request->input('name');
$asset->model()->associate($model);
$asset->name = $request->input('name');
// Check for a corresponding serial
if (($serials) && (array_key_exists($a, $serials))) {
$asset->serial = $serials[$a];
// Check for a corresponding serial
if (($serials) && (array_key_exists($a, $serials))) {
$asset->serial = $serials[$a];
}
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
$asset->asset_tag = $asset_tags[$a];
}
$asset->company_id = $companyId;
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->notes = $request->input('notes');
$asset->created_by = auth()->id();
$asset->status_id = request('status_id');
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = request('purchase_cost');
$asset->purchase_date = request('purchase_date', null);
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null);
$asset->requestable = request('requestable', 0);
$asset->rtd_location_id = request('rtd_location_id', null);
$asset->byod = request('byod', 0);
if (! empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths((int) $settings->audit_interval)->toDateString();
}
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
$asset->location_id = $request->input('rtd_location_id', null);
}
if ($request->has('use_cloned_image')) {
$cloned_model_img = Asset::select('image')->find($request->input('clone_image_from_id'));
if ($cloned_model_img) {
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
$new_image = 'assets/'.$new_image_name;
Storage::disk('public')->copy('assets/'.$cloned_model_img->image, $new_image);
$asset->image = $new_image_name;
}
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
$asset->asset_tag = $asset_tags[$a];
}
} else {
$asset = $request->handleImages($asset);
}
$asset->company_id = $companyId;
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->notes = $request->input('notes');
$asset->created_by = auth()->id();
$asset->status_id = request('status_id');
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = request('purchase_cost');
$asset->purchase_date = request('purchase_date', null);
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null);
$asset->requestable = request('requestable', 0);
$asset->rtd_location_id = request('rtd_location_id', null);
$asset->byod = request('byod', 0);
// Update custom fields in the database.
// Validation for these fields is handled through the AssetRequest form request
if (!empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths((int)$settings->audit_interval)->toDateString();
}
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
$asset->location_id = $request->input('rtd_location_id', null);
}
if ($request->has('use_cloned_image')) {
$cloned_model_img = Asset::select('image')->find($request->input('clone_image_from_id'));
if ($cloned_model_img) {
$new_image_name = 'clone-' . date('U') . '-' . $cloned_model_img->image;
$new_image = 'assets/' . $new_image_name;
Storage::disk('public')->copy('assets/' . $cloned_model_img->image, $new_image);
$asset->image = $new_image_name;
}
} else {
$asset = $request->handleImages($asset);
}
// Update custom fields in the database.
// Validation for these fields is handled through the AssetRequest form request
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
} else {
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
}
}
// Validate the asset before saving
// Note - it can be tempting to instead want to call saveOrFail(), to automatically throw when an object
// is invalid (and can't save). But this won't work, because Custom Fields _overrides_ the save() method
// to inject the Custom Field Rules into the $rules property right before invoking the _real_ save.
// so, instead, we have to catch failures on the 'else' clause and throw there.
if ($asset->isValid() && $asset->save()) {
$target = null;
$location = null;
if ($userId = request('assigned_user')) {
$target = User::find($userId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.user'));
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
}
$location = $target->location_id;
} elseif ($assetId = request('assigned_asset')) {
$target = Asset::find($assetId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.asset'));
}
$location = $target->location_id;
} elseif ($locationId = request('assigned_location')) {
$target = Location::find($locationId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.location'));
}
$location = $target->id;
}
if (isset($target)) {
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->input('name'), $location);
}
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
} else {
$asset->throwValidationException(); // we have to do this for the reason listed above - can't use saveOrFail()
$failures[] = join(",", $asset->getErrors()->all()); //TODO - this can probably go away soon
}
}
} catch (\Throwable $e) {
\Log::debug("Caught exception in multi-create - rolling back: " . $e->getMessage());
DB::rollBack();
throw $e;
}
DB::commit();
if($request->input('redirect_option') === 'back'){
// Validate the asset before saving
if ($asset->isValid() && $asset->save()) {
$target = null;
$location = null;
if ($userId = request('assigned_user')) {
$target = User::find($userId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.user'));
}
$location = $target->location_id;
} elseif ($assetId = request('assigned_asset')) {
$target = Asset::find($assetId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.asset'));
}
$location = $target->location_id;
} elseif ($locationId = request('assigned_location')) {
$target = Location::find($locationId);
if (!$target) {
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.location'));
}
$location = $target->id;
}
if (isset($target)) {
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
}
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
} else {
$failures[] = join(",", $asset->getErrors()->all());
}
}
if($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
session()->put(['checkout_to_type' => $request->input('checkout_to_type'),
session()->put(['checkout_to_type' => $request->get('checkout_to_type'),
'other_redirect' => 'model' ]);
@@ -454,7 +439,7 @@ class AssetsController extends Controller
// Update custom fields in the database.
// FIXME: No idea why this is returning a Builder error on db_column_name.
// Need to investigate and fix. Using static method for now.
$model = AssetModel::find($request->input('model_id'));
$model = AssetModel::find($request->get('model_id'));
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->element == 'checkbox' && !$request->has($field->db_column)) {
@@ -480,9 +465,9 @@ class AssetsController extends Controller
}
}
session()->put([
'redirect_option' => $request->input('redirect_option'),
'checkout_to_type' => $request->input('checkout_to_type'),
'other_redirect' => $request->input('redirect_option') === 'other_redirect' ? 'model' : null,
'redirect_option' => $request->get('redirect_option'),
'checkout_to_type' => $request->get('checkout_to_type'),
'other_redirect' => $request->get('redirect_option') === 'other_redirect' ? 'model' : null,
]);
@@ -552,9 +537,9 @@ class AssetsController extends Controller
*/
public function getAssetBySerial(Request $request) : RedirectResponse
{
$topsearch = ($request->input('topsearch')=="true");
$topsearch = ($request->get('topsearch')=="true");
if (!$asset = Asset::where('serial', '=', $request->input('serial'))->first()) {
if (!$asset = Asset::where('serial', '=', $request->get('serial'))->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('view', $asset);
@@ -570,8 +555,8 @@ class AssetsController extends Controller
*/
public function getAssetByTag(Request $request, $tag=null) : RedirectResponse
{
$tag = $tag ? $tag : $request->input('assetTag');
$topsearch = ($request->input('topsearch') == 'true');
$tag = $tag ? $tag : $request->get('assetTag');
$topsearch = ($request->get('topsearch') == 'true');
// Search for an exact and unique asset tag match
$assets = Asset::where('asset_tag', '=', $tag);
@@ -682,8 +667,8 @@ class AssetsController extends Controller
return (new Label())
->with('assets', collect([ $asset ]))
->with('settings', Setting::getSettings())
->with('template', request()->input('template'))
->with('offset', request()->input('offset'))
->with('template', request()->get('template'))
->with('offset', request()->get('offset'))
->with('bulkedit', false)
->with('count', 0);
}
@@ -982,7 +967,7 @@ class AssetsController extends Controller
$this->authorize('audit', Asset::class);
session()->put('redirect_option', $request->input('redirect_option'));
session()->put('redirect_option', $request->get('redirect_option'));
session()->put('other_redirect', 'audit');
@@ -588,7 +588,7 @@ class BulkAssetsController extends Controller
if ($request->session()->has('bulk_back_url')) {
$bulk_back_url = $request->session()->pull('bulk_back_url');
}
$assetIds = $request->input('ids');
$assetIds = $request->get('ids');
if(empty($assetIds)) {
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.delete.nothing_updated'));
@@ -652,11 +652,11 @@ class BulkAssetsController extends Controller
$target = $this->determineCheckoutTarget();
session()->put(['checkout_to_type' => $target]);
if (! is_array($request->input('selected_assets'))) {
if (! is_array($request->get('selected_assets'))) {
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
}
$asset_ids = array_filter($request->input('selected_assets'));
$asset_ids = array_filter($request->get('selected_assets'));
$assets = Asset::findOrFail($asset_ids);
@@ -692,14 +692,14 @@ class BulkAssetsController extends Controller
}
}
$checkout_at = date('Y-m-d H:i:s');
if (($request->filled('checkout_at')) && ($request->input('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->input('checkout_at');
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->get('checkout_at');
}
$expected_checkin = '';
if ($request->filled('expected_checkin')) {
$expected_checkin = $request->input('expected_checkin');
$expected_checkin = $request->get('expected_checkin');
}
$errors = [];
@@ -709,10 +709,10 @@ class BulkAssetsController extends Controller
// See if there is a status label passed
if ($request->filled('status_id')) {
$asset->status_id = $request->input('status_id');
$asset->status_id = $request->get('status_id');
}
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->input('note')), $asset->name, null);
$checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
//TODO - I think this logic is duplicated in the checkOut method?
if ($target->location_id != '') {
@@ -743,7 +743,7 @@ class BulkAssetsController extends Controller
public function restore(Request $request) : RedirectResponse
{
$this->authorize('update', Asset::class);
$assetIds = $request->input('ids');
$assetIds = $request->get('ids');
if (empty($assetIds)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
@@ -78,7 +78,6 @@ class CategoriesController extends Controller
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->alert_on_response = $request->input('alert_on_response', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$category->tag_color = $request->input('tag_color');
$category->notes = $request->input('notes');
$category->created_by = auth()->id();
@@ -133,7 +132,6 @@ class CategoriesController extends Controller
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->alert_on_response = $request->input('alert_on_response', '0');
$category->checkin_email = $request->input('checkin_email', '0');
$category->tag_color = $request->input('tag_color');
$category->notes = $request->input('notes');
$category = $request->handleImages($category);
@@ -60,7 +60,6 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone');
$company->fax = $request->input('fax');
$company->email = $request->input('email');
$company->tag_color = $request->input('tag_color');
$company->notes = $request->input('notes');
$company->created_by = auth()->id();
@@ -103,7 +102,6 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone');
$company->fax = $request->input('fax');
$company->email = $request->input('email');
$company->tag_color = $request->input('tag_color');
$company->notes = $request->input('notes');
$company = $request->handleImages($company);
@@ -98,7 +98,7 @@ class ComponentCheckinController extends Controller
event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
return Helper::getRedirectOption($request, $component->id, 'Components')
->with('success', trans('admin/components/message.checkin.success'));
@@ -80,8 +80,8 @@ class ComponentCheckoutController extends Controller
$max_to_checkout = $component->numRemaining();
// Make sure there are at least the requested number of components available to checkout
if ($max_to_checkout < $request->input('assigned_qty')) {
return redirect()->back()->withInput()->with('error', trans('admin/components/message.checkout.unavailable', ['remaining' => $max_to_checkout, 'requested' => $request->input('assigned_qty')]));
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(), [
@@ -115,19 +115,12 @@ class ComponentCheckoutController extends Controller
'note' => $request->input('note'),
]);
event(new CheckoutableCheckedOut(
$component,
$asset,
auth()->user(),
$request->input('note'),
[],
$component->checkout_qty,
));
event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note')));
$request->request->add(['checkout_to_type' => 'asset']);
$request->request->add(['assigned_asset' => $asset->id]);
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => $request->input('checkout_to_type')]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
return Helper::getRedirectOption($request, $component->id, 'Components')
->with('success', trans('admin/components/message.checkout.success'));
@@ -88,10 +88,10 @@ class ComponentsController extends Controller
$component = $request->handleImages($component);
if($request->input('redirect_option') === 'back'){
if($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
@@ -168,7 +168,7 @@ class ComponentsController extends Controller
$component = $request->handleImages($component);
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($component->save()) {
return Helper::getRedirectOption($request, $component->id, 'Components')
@@ -102,20 +102,12 @@ class ConsumableCheckoutController extends Controller
}
$consumable->checkout_qty = $quantity;
event(new CheckoutableCheckedOut(
$consumable,
$user,
auth()->user(),
$request->input('note'),
[],
$consumable->checkout_qty,
));
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
$request->request->add(['checkout_to_type' => 'user']);
$request->request->add(['assigned_user' => $user->id]);
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => $request->input('checkout_to_type')]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
// Redirect to the new consumable page
@@ -98,10 +98,10 @@ class ConsumablesController extends Controller
$consumable = $request->handleImages($consumable);
}
if($request->input('redirect_option') === 'back'){
if($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
@@ -175,7 +175,7 @@ class ConsumablesController extends Controller
$consumable = $request->handleImages($consumable);
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($consumable->save()) {
return Helper::getRedirectOption($request, $consumable->id, 'Consumables')
-4
View File
@@ -30,7 +30,6 @@ use App\Models\Consumable;
use App\Models\License;
use App\Models\Location;
use App\Models\Maintenance;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
@@ -53,7 +52,6 @@ abstract class Controller extends BaseController
'licenses' => License::class,
'locations' => Location::class,
'models' => AssetModel::class,
'suppliers' => Supplier::class,
'users' => User::class,
];
@@ -68,7 +66,6 @@ abstract class Controller extends BaseController
'licenses' => 'private_uploads/licenses/',
'locations' => 'private_uploads/locations/',
'models' => 'private_uploads/models/',
'suppliers' => 'private_uploads/suppliers/',
'users' => 'private_uploads/users/',
];
@@ -83,7 +80,6 @@ abstract class Controller extends BaseController
'licenses' => 'license',
'locations' => 'location',
'models' => 'model',
'suppliers' => 'supplier',
'users' => 'user',
];
+19 -19
View File
@@ -112,9 +112,9 @@ class CustomFieldsController extends Controller
if ($request->filled('custom_format')) {
$field->format = $request->input('custom_format');
$field->format = $request->get('custom_format');
} else {
$field->format = $request->input('format');
$field->format = $request->get('format');
}
if ($field->save()) {
@@ -225,34 +225,34 @@ class CustomFieldsController extends Controller
public function update(CustomFieldRequest $request, CustomField $field) : RedirectResponse
{
$this->authorize('update', CustomField::class);
$show_in_email = $request->input("show_in_email", 0);
$display_in_user_view = $request->input("display_in_user_view", 0);
$show_in_email = $request->get("show_in_email", 0);
$display_in_user_view = $request->get("display_in_user_view", 0);
// Override the display settings if the field is encrypted
if ($request->input("field_encrypted") == '1') {
if ($request->get("field_encrypted") == '1') {
$show_in_email = '0';
$display_in_user_view = '0';
}
$field->name = trim($request->input("name"));
$field->element = $request->input("element");
$field->field_values = $request->input("field_values");
$field->name = trim($request->get("name"));
$field->element = $request->get("element");
$field->field_values = $request->get("field_values");
$field->created_by = auth()->id();
$field->help_text = $request->input("help_text");
$field->help_text = $request->get("help_text");
$field->show_in_email = $show_in_email;
$field->is_unique = $request->input("is_unique", 0);
$field->is_unique = $request->get("is_unique", 0);
$field->display_in_user_view = $display_in_user_view;
$field->auto_add_to_fieldsets = $request->input("auto_add_to_fieldsets", 0);
$field->show_in_listview = $request->input("show_in_listview", 0);
$field->show_in_requestable_list = $request->input("show_in_requestable_list", 0);
$field->display_checkin = $request->input("display_checkin", 0);
$field->display_checkout = $request->input("display_checkout", 0);
$field->display_audit = $request->input("display_audit", 0);
$field->auto_add_to_fieldsets = $request->get("auto_add_to_fieldsets", 0);
$field->show_in_listview = $request->get("show_in_listview", 0);
$field->show_in_requestable_list = $request->get("show_in_requestable_list", 0);
$field->display_checkin = $request->get("display_checkin", 0);
$field->display_checkout = $request->get("display_checkout", 0);
$field->display_audit = $request->get("display_audit", 0);
if ($request->input('format') == 'CUSTOM REGEX') {
$field->format = $request->input('custom_format');
if ($request->get('format') == 'CUSTOM REGEX') {
$field->format = $request->get('custom_format');
} else {
$field->format = $request->input('format');
$field->format = $request->get('format');
}
if ($field->element == 'checkbox' || $field->element == 'radio'){
@@ -74,7 +74,7 @@ class CustomFieldsetsController extends Controller
{
$this->authorize('create', CustomField::class);
return view('custom_fields.fieldsets.view')->with('custom_fieldset', new CustomFieldset());
return view('custom_fields.fieldsets.edit')->with('item', new CustomFieldset());
}
/**
@@ -91,7 +91,7 @@ class CustomFieldsetsController extends Controller
$this->authorize('create', CustomField::class);
$fieldset = new CustomFieldset([
'name' => $request->input('name'),
'name' => $request->get('name'),
'created_by' => auth()->id(),
]);
@@ -127,7 +127,7 @@ class CustomFieldsetsController extends Controller
public function edit(CustomFieldset $fieldset) : View | RedirectResponse
{
$this->authorize('create', CustomField::class);
return view('custom_fields.fieldsets.view')->with('custom_fieldset', $fieldset);
return view('custom_fields.fieldsets.edit')->with('item', $fieldset);
}
/**
@@ -55,7 +55,6 @@ class DepartmentsController extends Controller
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
$department->location_id = ($request->filled('location_id') ? $request->input('location_id') : null);
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
$department->tag_color = $request->input('tag_color');
$department->notes = $request->input('notes');
$department = $request->handleImages($department);
@@ -158,7 +157,6 @@ class DepartmentsController extends Controller
$department->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
$department->phone = $request->input('phone');
$department->fax = $request->input('fax');
$department->tag_color = $request->input('tag_color');
$department->notes = $request->input('notes');
$department = $request->handleImages($department);
+7 -69
View File
@@ -7,7 +7,6 @@ use App\Models\Group;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View;
use \App\Models\User;
/**
* This controller handles all actions related to User Groups for
@@ -44,24 +43,9 @@ class GroupsController extends Controller
$permissions = config('permissions');
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
$selectedPermissions = $request->old('permissions', $groupPermissions);
$users_query = User::query()
->select(['users.id', 'users.first_name', 'users.last_name', 'users.username'])
->where('show_in_list', 1)
->whereNull('deleted_at');
$users_count = $users_query->count();
$users = collect();
if ($users_count <= config('app.max_unpaginated_records')) {
$users = $users_query->orderBy('first_name', 'asc')->orderBy('last_name', 'asc')->get();
}
// Show the page
return view('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions'))
->with('group', $group)
->with('associated_users', collect())
->with('unselected_users', $users)
->with('all_users_count', $users_count);
return view('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions'))->with('group', $group);
}
/**
@@ -76,23 +60,12 @@ class GroupsController extends Controller
// create a new group instance
$group = new Group();
$group->name = $request->input('name');
if ($request->filled('permission')) {
$group->permissions = json_encode($request->array('permission'));
} else {
$group->permissions = null;
}
$group->permissions = json_encode($request->input('permission'));
$group->created_by = auth()->id();
$group->notes = $request->input('notes');
if ($group->save()) {
if ($request->filled('users_to_sync')) {
$associated_users = explode(',',$request->input('users_to_sync'));
$group->users()->sync($associated_users);
}
$group->users()->sync($request->input('associated_users'));
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
}
@@ -115,35 +88,11 @@ class GroupsController extends Controller
if ((!is_array($groupPermissions)) || (!$groupPermissions)) {
$groupPermissions = [];
}
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
$associated_users = $group->users()->get();
$users_query = User::query()
->select(['users.id', 'users.first_name', 'users.last_name', 'users.username'])
->where('show_in_list', 1)
->whereNull('deleted_at');
$users_count = $users_query->count();
$associated_users = collect();
$unselected_users = collect();
if ($users_count <= config('app.max_unpaginated_records')) {
$associated_users = $group->users()->where('show_in_list', 1)->orderBy('first_name', 'asc')->orderBy('last_name', 'asc')->get();
// Get the unselected users
$unselected_users = User::query()
->select(['users.id', 'users.first_name', 'users.last_name', 'users.username'])
->where('show_in_list', 1)
->whereNotIn('id', $associated_users->pluck('id')->toArray())
->orderBy('first_name', 'asc')
->orderBy('last_name', 'asc')
->get();
}
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'))
->with('associated_users', $associated_users)
->with('unselected_users', $unselected_users)
->with('all_users_count', $users_count);
//dd($associated_users->toArray());
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'))->with('associated_users', $associated_users);
}
/**
@@ -157,24 +106,13 @@ class GroupsController extends Controller
public function update(Request $request, Group $group) : RedirectResponse
{
$group->name = $request->input('name');
if ($request->filled('permission')) {
$group->permissions = json_encode($request->array('permission'));
} else {
$group->permissions = null;
}
$group->permissions = json_encode($request->input('permission'));
$group->notes = $request->input('notes');
if (! config('app.lock_passwords')) {
if ($group->save()) {
if ($request->has('users_to_sync')) {
$associated_users = explode(',',$request->input('users_to_sync'));
$group->users()->sync($associated_users);
}
$group->users()->sync($request->input('associated_users'));
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.update'));
}
@@ -47,7 +47,7 @@ class CheckoutKitController extends Controller
*/
public function store(Request $request, $kit_id)
{
$user_id = e($request->input('user_id'));
$user_id = e($request->get('user_id'));
if (is_null($user = User::find($user_id))) {
return redirect()->back()->with('error', trans('admin/users/message.user_not_found'));
}
+1 -1
View File
@@ -81,7 +81,7 @@ class LabelsController extends Controller
$settings = Setting::getSettings();
if (request()->has('settings')) {
$overrides = request()->input('settings');
$overrides = request()->get('settings');
foreach ($overrides as $key => $value) {
$settings->$key = $value;
}
@@ -97,8 +97,8 @@ class LicenseCheckinController extends Controller
$licenseSeat->unreassignable_seat = true;
}
session()->put(['redirect_option' => $request->input('redirect_option')]);
if ($request->input('redirect_option') === 'target'){
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($request->get('redirect_option') === 'target'){
session()->put(['checkout_to_type' => 'user']);
}
@@ -96,13 +96,13 @@ class LicenseCheckoutController extends Controller
session()->put(['checkout_to_type' => 'asset']);
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => 'asset']);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
} elseif ($request->filled('assigned_to')) {
session()->put(['checkout_to_type' => 'user']);
$checkoutTarget = $this->checkoutToUser($licenseSeat);
$request->request->add(['assigned_user' => $checkoutTarget->id]);
session()->put(['redirect_option' => $request->input('redirect_option'), 'checkout_to_type' => 'user']);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
}
@@ -102,10 +102,10 @@ class LicensesController extends Controller
$license->created_by = auth()->id();
$license->min_amt = $request->input('min_amt');
if($request->input('redirect_option') === 'back'){
if($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
if ($license->save()) {
@@ -183,7 +183,7 @@ class LicensesController extends Controller
$license->category_id = $request->input('category_id');
$license->min_amt = $request->input('min_amt');
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($license->save()) {
return Helper::getRedirectOption($request, $license->id, 'Licenses')
@@ -82,7 +82,6 @@ class LocationsController extends Controller
$location->created_by = auth()->id();
$location->phone = request('phone');
$location->fax = request('fax');
$location->tag_color = $request->input('tag_color');
$location->notes = $request->input('notes');
$location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
@@ -157,7 +156,6 @@ class LocationsController extends Controller
$location->fax = request('fax');
$location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id');
$location->tag_color = $request->input('tag_color');
$location->notes = $request->input('notes');
// Only scope the location if the setting is enabled
@@ -68,6 +68,12 @@ class MaintenancesController extends Controller
{
$this->authorize('update', Asset::class);
\Log::error(print_r($request->input('selected_assets[]'), true));
if (!$request->filled('selected_assets')) {
return redirect()->back()->withInput()->with('error', 'No assets were selected.');
}
$assets = Asset::whereIn('id', $request->input('selected_assets'))->get();
// Loop through the selected assets
@@ -101,7 +101,6 @@ class ManufacturersController extends Controller
$manufacturer->support_email = $request->input('support_email');
$manufacturer->notes = $request->input('notes');
$manufacturer = $request->handleImages($manufacturer);
$manufacturer->tag_color = $request->input('tag_color');
if ($manufacturer->save()) {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.create.success'));
@@ -143,7 +142,6 @@ class ManufacturersController extends Controller
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
$manufacturer->support_phone = $request->input('support_phone');
$manufacturer->support_email = $request->input('support_email');
$manufacturer->tag_color = $request->input('tag_color');
$manufacturer->notes = $request->input('notes');
// Set the model's image property to null if the image is being deleted
+12 -21
View File
@@ -5,7 +5,6 @@ namespace App\Http\Controllers;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Transformers\ProfileTransformer;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\CurrentInventory;
@@ -35,7 +34,7 @@ class ProfileController extends Controller
*/
public function getIndex() : View
{
$this->authorize('self.profile');
$user = auth()->user();
return view('account/profile', compact('user'));
}
@@ -48,25 +47,20 @@ class ProfileController extends Controller
*/
public function postIndex(ImageUploadRequest $request) : RedirectResponse
{
$this->authorize('self.profile');
$user = auth()->user();
if ((Gate::allows('self.profile')) && (! config('app.lock_passwords'))) {
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->website = $request->input('website');
$user->gravatar = $request->input('gravatar');
$user->phone = $request->input('phone');
}
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->website = $request->input('website');
$user->gravatar = $request->input('gravatar');
$user->skin = $request->input('skin');
$user->phone = $request->input('phone');
$user->enable_sounds = $request->input('enable_sounds', false);
$user->enable_confetti = $request->input('enable_confetti', false);
$user->link_light_color = $request->input('link_light_color', '#296282');
$user->link_dark_color = $request->input('link_dark_color', '#296282');
$user->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
$user->locale = $request->input('locale');
if (! config('app.lock_passwords')) {
$user->locale = $request->input('locale');
}
if ((Gate::allows('self.two_factor')) && ((Setting::getSettings()->two_factor_enabled == '1') && (! config('app.lock_passwords')))) {
$user->two_factor_optin = $request->input('two_factor_optin', '0');
@@ -255,10 +249,7 @@ class ProfileController extends Controller
$logentry = Actionlog::where('filename', $filename)->first();
// Make sure the user has permission to view this file
// Also allow if the user (manager) able to view both users and assets
$allowed_to_view_users_assets = Gate::allows('view', User::class) && Gate::allows('view', Asset::class);
if (auth()->id() != $logentry->target_id && !$allowed_to_view_users_assets) {
if (auth()->id() != $logentry->target_id) {
return redirect()->route('account')->with('error', trans('general.generic_model_not_found', ['model' => 'file']));
}
+50 -112
View File
@@ -3,21 +3,12 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Mail\CheckoutAccessoryMail;
use App\Mail\CheckoutAssetMail;
use App\Mail\CheckoutComponentMail;
use App\Mail\CheckoutConsumableMail;
use App\Mail\CheckoutLicenseMail;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Checkoutable;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\Maintenance;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
@@ -27,11 +18,9 @@ use App\Models\License;
use App\Models\ReportTemplate;
use App\Models\Setting;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail;
use \Illuminate\Contracts\View\View;
use League\Csv\Reader;
@@ -818,7 +807,7 @@ class ReportsController extends Controller
}
if ($request->filled('eol')) {
$row[] = ($asset->asset_eol_date != '') ? $asset->asset_eol_date : '';
$row[] = ($asset->purchase_date != '') ? $asset->asset_eol_date : '';
}
if ($request->filled('warranty')) {
@@ -1127,32 +1116,34 @@ class ReportsController extends Controller
$this->authorize('reports.view');
$showDeleted = $deleted == 'deleted';
$query = CheckoutAcceptance::Pending()
$query = CheckoutAcceptance::pending()
->where('checkoutable_type', 'App\Models\Asset')
->with([
'checkoutable' => function (MorphTo $query) {
$query->withTrashed()->morphWith([
Asset::class => ['model.category', 'assignedTo', 'company'],
Accessory::class => ['category','checkouts', 'company'],
LicenseSeat::class => ['user', 'license'],
Component::class => ['assignedTo', 'company'],
Consumable::class => ['company'],
]);
$query->morphWith([
AssetModel::class => ['model'],
Company::class => ['company'],
Asset::class => ['assignedTo'],
])->with('model.category');
},
'assignedTo' => function($query){
$query->withTrashed();
}
])->orderByDesc('checkout_acceptances.created_at');
]);
if ($showDeleted) {
$query->withTrashed();
}
$itemsForReport = $query->get()
->filter(fn ($unaccepted) => $unaccepted->checkoutable)
->map(fn ($unaccepted) => Checkoutable::fromAcceptance($unaccepted));
$assetsForReport = $query->get()
->map(function ($acceptance) {
return [
'assetItem' => $acceptance->checkoutable,
'acceptance' => $acceptance,
];
});
return view('reports/unaccepted_assets', compact('itemsForReport','showDeleted' ));
return view('reports/unaccepted_assets', compact('assetsForReport','showDeleted' ));
}
/**
@@ -1164,79 +1155,41 @@ class ReportsController extends Controller
public function sentAssetAcceptanceReminder(Request $request) : RedirectResponse
{
$this->authorize('reports.view');
$id = $request->input('acceptance_id');
$query = CheckoutAcceptance::query()
->with([
'checkoutable' => function (MorphTo $query) {
$query->withTrashed()->morphWith([
Asset::class => ['model.category', 'assignedTo', 'company', 'checkouts'],
Accessory::class => ['category', 'company', 'checkouts'],
LicenseSeat::class => ['user', 'license', 'checkouts'],
Component::class => ['assignedTo', 'company', 'checkouts'],
Consumable::class => ['company', 'checkouts'],
]);
},
'assignedTo' => fn ($q) => $q->withTrashed(),
])
->pending();
$acceptance = $query->find($id);
if (!$acceptance) {
if (!$acceptance = CheckoutAcceptance::pending()->find($request->input('acceptance_id'))) {
Log::debug('No pending acceptances');
// Redirect to the unaccepted items report page with error
// Redirect to the unaccepted assets report page with error
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
}
$item = $acceptance->checkoutable;
$assignee = $acceptance->assignedTo ?? $item->assignedTo ?? null;
$email = $assignee?->email;
$locale = $assignee?->locale;
Log::debug(print_r($acceptance, true));
$assetItem = $acceptance->checkoutable;
Log::debug(print_r($assetItem, true));
if (is_null($acceptance->created_at)){
Log::debug('No acceptance created_at');
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
} else {
if($item instanceof LicenseSeat){
$logItem_res = $item->license->checkouts()->with('adminuser')->where('created_at', '=', $acceptance->created_at)->get();
}
else{
$logItem_res = $item->checkouts()->with('adminuser')->where('created_at', '=', $acceptance->created_at)->get();
}
$logItem_res = $assetItem->checkouts()->where('created_at', '=', $acceptance->created_at)->get();
if ($logItem_res->isEmpty()){
Log::debug('Acceptance date mismatch');
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
}
$logItem = $logItem_res[0];
}
$email = $assetItem->assignedTo?->email;
$locale = $assetItem->assignedTo?->locale;
if (is_null($email) || $email === '') {
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_email'));
}
$mailable = $this->getCheckoutMailType($acceptance, $logItem);
Mail::to($email)->send($mailable->locale($locale));
Mail::to($email)->send((new CheckoutAssetMail($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note, firstTimeSending: false))->locale($locale));
return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent'));
}
private function getCheckoutMailType(CheckoutAcceptance $acceptance, $logItem) : Mailable
{
$lookup = [
Accessory::class => CheckoutAccessoryMail::class,
Asset::class => CheckoutAssetMail::class,
LicenseSeat::class => CheckoutLicenseMail::class,
Consumable::class => CheckoutConsumableMail::class,
Component::class => CheckoutComponentMail::class,
];
$mailable= $lookup[get_class($acceptance->checkoutable)];
return new $mailable(
$acceptance->checkoutable,
$acceptance->checkedOutTo ?? $acceptance->assignedTo,
$logItem->adminuser,
$acceptance,
$acceptance->note,
firstTimeSending: false,
);
}
/**
* sentAssetAcceptanceReminder
*
@@ -1268,43 +1221,31 @@ class ReportsController extends Controller
public function postAssetAcceptanceReport($deleted = false) : Response
{
$this->authorize('reports.view');
$showDeleted = request('deleted') === 'deleted';;
$showDeleted = $deleted == 'deleted';
/**
* Get all assets with pending checkout acceptances
*/
if($showDeleted) {
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->withTrashed()->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model'])->get();
} else {
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model'])->get();
}
$acceptances = CheckoutAcceptance::pending()
->with([
'checkoutable' => function (MorphTo $acceptance) {
$acceptance->withTrashed()->morphWith([
Asset::class => ['model.category', 'assignedTo', 'company'],
Accessory::class => ['category','checkouts', 'company'],
LicenseSeat::class => ['user', 'license'],
Component::class => ['assignedTo', 'company'],
Consumable::class => ['company'],
]);
},
'assignedTo',
])->orderByDesc('checkout_acceptances.created_at');
if ($showDeleted) {
$acceptances->withTrashed();
}
$itemsForReport = $acceptances->get()
->filter(fn ($unaccepted) => $unaccepted->checkoutable)
->map(fn ($unaccepted) => Checkoutable::fromAcceptance($unaccepted));
$assetsForReport = $acceptances
->filter(function($acceptance) {
return $acceptance->checkoutable_type == 'App\Models\Asset';
})
->map(function($acceptance) {
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
});
$rows = [];
$header = [
trans('general.date'),
trans('general.type'),
trans('admin/companies/table.title'),
trans('general.category'),
trans('admin/hardware/form.model'),
trans('general.name'),
trans('admin/hardware/form.name'),
trans('admin/hardware/table.asset_tag'),
trans('admin/hardware/table.checkoutto'),
];
@@ -1312,19 +1253,16 @@ class ReportsController extends Controller
$header = array_map('trim', $header);
$rows[] = implode(',', $header);
foreach ($itemsForReport as $item) {
foreach ($assetsForReport as $item) {
if ($item != null){
if ($item['assetItem'] != null){
$row = [ ];
$row[] = str_replace(',', '', $item->acceptance->created_at);
$row[] = str_replace(',', '', $item->type);
$row[] = str_replace(',', '', $item->plain_text_company);
$row[] = str_replace(',', '', $item->plain_text_category);
$row[] = str_replace(',', '', $item->plain_text_model);
$row[] = str_replace(',', '', $item->plain_text_name);
$row[] = str_replace(',', '', $item->asset_tag);
$row[] = str_replace(',', '', ($item->acceptance->assignedto) ? $item->acceptance->assignedto->display_name : trans('admin/reports/general.deleted_user'));
$row[] = str_replace(',', '', e($item['assetItem']->model->category->name));
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
$row[] = str_replace(',', '', e($item['assetItem']->name));
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user')));
$rows[] = implode(',', $row);
}
}
+237 -17
View File
@@ -6,31 +6,38 @@ use App\Helpers\Helper;
use App\Helpers\StorageHelper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsSamlRequest;
use App\Http\Requests\StoreLabelSettings;
use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\StoreLdapSettings;
use App\Http\Requests\StoreLocalizationSettings;
use App\Http\Requests\StoreNotificationSettings;
use App\Http\Requests\StoreLabelSettings;
use App\Http\Requests\StoreSecuritySettings;
use App\Models\Asset;
use App\Models\CustomField;
use App\Models\Group;
use App\Models\Labels\Label as LabelModel;
use App\Models\Setting;
use App\Models\Asset;
use App\Models\User;
use App\Notifications\FirstAdminNotification;
use App\Notifications\MailTest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\JsonResponse;
use \Illuminate\Contracts\View\View;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use \Illuminate\Contracts\View\View;
/**
* This controller handles all actions related to Settings for
@@ -40,6 +47,224 @@ use \Illuminate\Contracts\View\View;
*/
class SettingsController extends Controller
{
/**
* Checks to see whether or not the database has a migrations table
* and a user, otherwise display the setup view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\Response
*/
public function getSetupIndex() : View
{
$start_settings['php_version_min'] = false;
if (version_compare(PHP_VERSION, config('app.min_php'), '<')) {
return response('<center><h1>This software requires PHP version '.config('app.min_php').' or greater. This server is running '.PHP_VERSION.'. </h1><h2>Please upgrade PHP on this server and try again. </h2></center>', 500);
}
try {
$conn = DB::select('select 2 + 2');
$start_settings['db_conn'] = true;
$start_settings['db_name'] = DB::connection()->getDatabaseName();
$start_settings['db_error'] = null;
} catch (\PDOException $e) {
$start_settings['db_conn'] = false;
$start_settings['db_name'] = config('database.connections.mysql.database');
$start_settings['db_error'] = $e->getMessage();
}
$start_settings['url_config'] = trim(config('app.url'), '/'). '/setup';
$start_settings['real_url'] = request()->url();
$start_settings['url_valid'] = $start_settings['url_config'] === $start_settings['real_url'];
$start_settings['php_version_min'] = true;
// Curl the .env file to make sure it's not accessible via a browser
$start_settings['env_exposed'] = $this->dotEnvFileIsExposed();
if (App::Environment('production') && (true == config('app.debug'))) {
$start_settings['debug_exposed'] = true;
} else {
$start_settings['debug_exposed'] = false;
}
$environment = app()->environment();
if ('production' != $environment) {
$start_settings['env'] = $environment;
$start_settings['prod'] = false;
} else {
$start_settings['env'] = $environment;
$start_settings['prod'] = true;
}
$start_settings['owner'] = '';
if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
// This *should* be an array, but we've seen this return a bool in some chrooted environments
if (is_array($owner)) {
$start_settings['owner'] = $owner['name'];
}
}
if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
$start_settings['owner_is_admin'] = true;
} else {
$start_settings['owner_is_admin'] = false;
}
$start_settings['writable'] = $this->storagePathIsWritable();
$start_settings['gd'] = extension_loaded('gd');
return view('setup/index')
->with('step', 1)
->with('start_settings', $start_settings)
->with('section', 'Pre-Flight Check');
}
/**
* Determine if the .env file accessible via a browser.
*
* @return bool This method will return true when exceptions (such as curl exception) is thrown.
* Check the log files to see more details about the exception.
*/
protected function dotEnvFileIsExposed() : bool
{
try {
return Http::withoutVerifying()->timeout(10)
->accept('*/*')
->get(URL::to('.env'))
->successful();
} catch (\Exception $e) {
Log::debug($e->getMessage());
return true;
}
}
/**
* Determine if the app storage path is writable.
*/
protected function storagePathIsWritable(): bool
{
return File::isWritable(storage_path()) &&
File::isWritable(storage_path('framework')) &&
File::isWritable(storage_path('framework/cache')) &&
File::isWritable(storage_path('framework/sessions')) &&
File::isWritable(storage_path('framework/views')) &&
File::isWritable(storage_path('logs'));
}
/**
* Save the first admin user from Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
*
*/
public function postSaveFirstAdmin(SetupUserRequest $request) : RedirectResponse
{
$user = new User();
$user->first_name = $data['first_name'] = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->email = $data['email'] = $request->input('email');
$user->activated = 1;
$permissions = ['superuser' => 1];
$user->permissions = json_encode($permissions);
$user->username = $data['username'] = $request->input('username');
$user->password = bcrypt($request->input('password'));
$data['password'] = $request->input('password');
$settings = new Setting();
$settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0);
$settings->site_name = $request->input('site_name');
$settings->alert_email = $request->input('email');
$settings->alerts_enabled = 1;
$settings->pwd_secure_min = 10;
$settings->brand = 1;
$settings->locale = $request->input('locale', 'en-US');
$settings->default_currency = $request->input('default_currency', 'USD');
$settings->created_by = 1;
$settings->email_domain = $request->input('email_domain');
$settings->email_format = $request->input('email_format');
$settings->next_auto_tag_base = 1;
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
$settings->zerofill_count = $request->input('zerofill_count') ?: 0;
if ((! $user->isValid()) || (! $settings->isValid())) {
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
} else {
$user->save();
Auth::login($user, true);
$settings->save();
if ($request->input('email_creds') == '1') {
$data = [];
$data['email'] = $user->email;
$data['username'] = $user->username;
$data['first_name'] = $user->first_name;
$data['last_name'] = $user->last_name;
$data['password'] = $request->input('password');
$user->notify(new FirstAdminNotification($data));
}
return redirect()->route('setup.done');
}
}
/**
* Return the admin user creation form in Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function getSetupUser() : View
{
return view('setup/user')
->with('step', 3)
->with('section', 'Create a User');
}
/**
* Return the view that tells the user that the Setup is done.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function getSetupDone() : View
{
return view('setup/done')
->with('step', 4)
->with('section', 'Done!');
}
/**
* Migrate the database tables, and return the output
* to a view for Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function getSetupMigrate() : View
{
Artisan::call('migrate', ['--force' => true]);
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
Artisan::call('passport:install', ['--no-interaction' => true]);
}
return view('setup/migrate')
->with('output', 'Databases installed!')
->with('step', 2)
->with('section', 'Create Database Tables');
}
/**
* Return a view that shows some of the key settings.
@@ -114,7 +339,7 @@ class SettingsController extends Controller
$setting->email_domain = $request->input('email_domain');
$setting->email_format = $request->input('email_format');
$setting->username_format = $request->input('username_format');
$setting->require_accept_signature = $request->input('require_accept_signature', '0');
$setting->require_accept_signature = $request->input('require_accept_signature');
$setting->show_assigned_assets = $request->input('show_assigned_assets', '0');
if (! config('app.lock_passwords')) {
$setting->login_note = $request->input('login_note');
@@ -174,10 +399,12 @@ class SettingsController extends Controller
}
$setting->brand = $request->input('brand', '1');
$setting->header_color = $request->input('header_color');
$setting->support_footer = $request->input('support_footer');
$setting->version_footer = $request->input('version_footer');
$setting->footer_text = $request->input('footer_text');
$setting->skin = $request->input('skin');
$setting->allow_user_skin = $request->input('allow_user_skin', '0');
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0');
$setting->logo_print_assets = $request->input('logo_print_assets', '0');
$setting->load_remote = $request->input('load_remote', 0);
@@ -191,11 +418,6 @@ class SettingsController extends Controller
$request->validate(['site_name' => 'required']);
}
$setting->header_color = $request->input('header_color');
$setting->link_light_color = $request->input('link_light_color', '#296282');
$setting->link_dark_color = $request->input('link_dark_color', '#296282');
$setting->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
$setting->site_name = $request->input('site_name', 'Snipe-IT');
$setting->custom_css = $request->input('custom_css');
@@ -367,7 +589,6 @@ class SettingsController extends Controller
$setting->time_display_format = $request->input('time_display_format');
$setting->digit_separator = $request->input('digit_separator');
$setting->name_display_format = $request->input('name_display_format');
$setting->week_start = $request->input('week_start', 0);
if ($setting->save()) {
return redirect()->route('settings.index')
@@ -551,7 +772,6 @@ class SettingsController extends Controller
$setting->label2_asset_logo = $request->input('label2_asset_logo');
$setting->label2_1d_type = $request->input('label2_1d_type');
$setting->label2_2d_type = $request->input('label2_2d_type');
$setting->label2_2d_prefix = $request->input('label2_2d_prefix');
$setting->label2_2d_target = $request->input('label2_2d_target');
$setting->label2_fields = $request->input('label2_fields');
$setting->label2_empty_row_count = $request->input('label2_empty_row_count');
-270
View File
@@ -1,270 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\SetupUserRequest;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\FirstAdminNotification;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;
use \Illuminate\Contracts\View\View;
/**
* This controller handles all actions related to Settings for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class SetupController extends Controller
{
/**
* Checks to see whether or not the database has a migrations table
* and a user, otherwise display the setup view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\Response
*/
public function getSetupIndex() : View
{
$start_settings['php_version_min'] = false;
if (version_compare(PHP_VERSION, config('app.min_php'), '<')) {
return response('<center><h1>This software requires PHP version '.config('app.min_php').' or greater. This server is running '.PHP_VERSION.'. </h1><h2>Please upgrade PHP on this server and try again. </h2></center>', 500);
}
try {
$conn = DB::select('select 2 + 2');
$start_settings['db_conn'] = true;
$start_settings['db_name'] = DB::connection()->getDatabaseName();
$start_settings['db_error'] = null;
} catch (\PDOException $e) {
$start_settings['db_conn'] = false;
$start_settings['db_name'] = config('database.connections.mysql.database');
$start_settings['db_error'] = $e->getMessage();
}
$start_settings['url_config'] = trim(config('app.url'), '/'). '/setup';
$start_settings['real_url'] = request()->url();
$start_settings['url_valid'] = $start_settings['url_config'] === $start_settings['real_url'];
$start_settings['php_version_min'] = true;
// Curl the .env file to make sure it's not accessible via a browser
$start_settings['env_exposed'] = $this->dotEnvFileIsExposed();
if (App::Environment('production') && (true == config('app.debug'))) {
$start_settings['debug_exposed'] = true;
} else {
$start_settings['debug_exposed'] = false;
}
$environment = app()->environment();
if ('production' != $environment) {
$start_settings['env'] = $environment;
$start_settings['prod'] = false;
} else {
$start_settings['env'] = $environment;
$start_settings['prod'] = true;
}
$start_settings['owner'] = '';
if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
// This *should* be an array, but we've seen this return a bool in some chrooted environments
if (is_array($owner)) {
$start_settings['owner'] = $owner['name'];
}
}
if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
$start_settings['owner_is_admin'] = true;
} else {
$start_settings['owner_is_admin'] = false;
}
$start_settings['writable'] = $this->storagePathIsWritable();
$start_settings['gd'] = extension_loaded('gd');
return view('setup/index')
->with('step', 1)
->with('start_settings', $start_settings)
->with('section', trans('general.setup_config_check'))
->with('icon', 'fa-regular fa-rectangle-list');
}
/**
* Determine if the .env file accessible via a browser.
*
* @return bool This method will return true when exceptions (such as curl exception) is thrown.
* Check the log files to see more details about the exception.
*/
protected function dotEnvFileIsExposed() : bool
{
try {
return Http::withoutVerifying()->timeout(10)
->accept('*/*')
->get(URL::to('.env'))
->successful();
} catch (\Exception $e) {
Log::debug($e->getMessage());
return true;
}
}
/**
* Determine if the app storage path is writable.
*/
protected function storagePathIsWritable(): bool
{
return File::isWritable(storage_path()) &&
File::isWritable(storage_path('framework')) &&
File::isWritable(storage_path('framework/cache')) &&
File::isWritable(storage_path('framework/sessions')) &&
File::isWritable(storage_path('framework/views')) &&
File::isWritable(storage_path('logs'));
}
/**
* Save the first admin user from Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
*
*/
public function postSaveFirstAdmin(SetupUserRequest $request) : RedirectResponse
{
$user = new User();
$user->first_name = $data['first_name'] = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->email = $data['email'] = $request->input('email');
$user->activated = 1;
$permissions = ['superuser' => 1];
$user->permissions = json_encode($permissions);
$user->username = $data['username'] = $request->input('username');
$user->password = bcrypt($request->input('password'));
$data['password'] = $request->input('password');
$settings = new Setting();
$settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0);
$settings->site_name = $request->input('site_name');
$settings->alert_email = $request->input('email');
$settings->alerts_enabled = 1;
$settings->pwd_secure_min = 10;
$settings->brand = 1;
$settings->link_light_color = $request->input('link_light_color', '#296282');
$settings->link_dark_color = $request->input('link_dark_color', '#296282');
$settings->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
$settings->locale = $request->input('locale', 'en-US');
$settings->default_currency = $request->input('default_currency', 'USD');
$settings->created_by = 1;
$settings->email_domain = $request->input('email_domain');
$settings->email_format = $request->input('email_format');
$settings->next_auto_tag_base = 1;
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
$settings->zerofill_count = $request->input('zerofill_count') ?: 0;
if ((! $user->isValid()) || (! $settings->isValid())) {
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
} else {
$user->save();
Auth::login($user, true);
$settings->save();
if ($request->input('email_creds') == '1') {
$data = [];
$data['email'] = $user->email;
$data['username'] = $user->username;
$data['first_name'] = $user->first_name;
$data['last_name'] = $user->last_name;
$data['password'] = $request->input('password');
$user->notify(new FirstAdminNotification($data));
}
return redirect()
->route('setup.done')
->with('section', trans('general.setup_create_admin'))
->with('icon', 'fa-solid fa-champagne-glasses')
->with('success', trans('admin/settings/general.create_admin_success'));
}
}
/**
* Return the admin user creation form in Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function getSetupUser() : View
{
return view('setup/user')
->with('step', 3)
->with('section', trans('general.setup_create_admin'))
->with('icon', 'fa-solid fa-user-plus');
}
/**
* Return the view that tells the user that the Setup is done.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function getSetupDone() : View
{
return view('setup/done')
->with('success', trans('general.create_admin_success'))
->with('step', 4)
->with('icon', 'fa-solid fa-champagne-glasses fa-shake')
->with('section', trans('general.setup_done'));
}
/**
* Migrate the database tables, and return the output
* to a view for Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v3.0]
*/
public function setupMigrate()
{
Artisan::call('migrate', ['--force' => true]);
$output = Artisan::output();
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
Artisan::call('passport:install', ['--no-interaction' => true]);
}
return view('setup/migrate')
->with('success', trans('general.create_admin_success'))
->with('output', trim($output))
->with('step', 2)
->with('section', trans('general.setup_create_database'))
->with('icon', 'fa-solid fa-database');
}
}
@@ -67,7 +67,6 @@ class SuppliersController extends Controller
$supplier->phone = request('phone');
$supplier->fax = request('fax');
$supplier->email = request('email');
$supplier->tag_color = $request->input('tag_color');
$supplier->notes = request('notes');
$supplier->url = $supplier->addhttp(request('url'));
$supplier->created_by = auth()->id();
@@ -112,7 +111,6 @@ class SuppliersController extends Controller
$supplier->fax = request('fax');
$supplier->email = request('email');
$supplier->url = $supplier->addhttp(request('url'));
$supplier->tag_color = $request->input('tag_color');
$supplier->notes = request('notes');
$supplier = $request->handleImages($supplier);
@@ -2,11 +2,9 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Helpers\StorageHelper;
use App\Http\Requests\UploadFileRequest;
use App\Models\Actionlog;
use App\Models\Import;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -56,7 +54,7 @@ class UploadedFilesController extends Controller
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile(self::$map_storage_path[$object_type], self::$map_file_prefix[$object_type].'-'.$object->id, $file);
$files[] = $file_name;
$object->logUpload($file_name, $request->input('notes'));
$object->logUpload($file_name, $request->get('notes'));
}
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
@@ -157,31 +155,7 @@ class UploadedFilesController extends Controller
}
// The file doesn't seem to really exist, so report an error
return redirect()->back()->withFragment('files')->with('error', trans_choice('general.file_upload_status.delete.error', 1));
}
public function downloadImport(Import $import) {
$this->authorize('import');
if ($import = Import::find($import->id)) {
if ((auth()->user()->id != $import->created_by) && (!auth()->user()->isSuperUser())) {
return redirect()->back()->with('error', trans('general.file_upload_status.file_not_found'));
}
if (config('filesystems.default') == 's3_private') {
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/imports/' . $import->file_path, now()->addMinutes(5)));
}
if (Storage::exists('private_uploads/imports/' . $import->file_path)) {
return response()->download(config('app.private_uploads') . '/imports/' . $import->file_path);
}
}
return redirect()->back()->with('error', trans('general.file_upload_status.file_not_found'));
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.error', 1));
}
@@ -169,7 +169,6 @@ class BulkUsersController extends Controller
->conditionallyAddItem('remote')
->conditionallyAddItem('ldap_import')
->conditionallyAddItem('activated')
->conditionallyAddItem('display_name')
->conditionallyAddItem('start_date')
->conditionallyAddItem('end_date')
->conditionallyAddItem('city')
@@ -215,10 +214,6 @@ class BulkUsersController extends Controller
$this->update_array['locale'] = null;
}
if ($request->input('null_display_name')=='1') {
$this->update_array['display_name'] = null;
}
if (! $manager_conflict) {
$this->conditionallyAddItem('manager_id');
}
@@ -234,11 +229,8 @@ class BulkUsersController extends Controller
// Only sync groups if groups were selected
if ($request->filled('groups')) {
foreach ($users as $user) {
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
$user->groups()->sync($request->input('groups'));
}
$user->groups()->sync($request->input('groups'));
}
}
@@ -320,9 +312,7 @@ class BulkUsersController extends Controller
foreach ($users as $user) {
$user->accessories()->sync([]);
if ($request->input('delete_user')=='1') {
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
$user->delete();
}
$user->delete();
}
}
+8 -13
View File
@@ -56,7 +56,7 @@ class UsersController extends Controller
public function create(Request $request)
{
$this->authorize('create', User::class);
$groups = Group::orderBy('name', 'asc')->pluck('name', 'id');
$groups = Group::pluck('name', 'id');
$userGroups = collect();
@@ -130,10 +130,10 @@ class UsersController extends Controller
// we have to invoke the form request here to handle image uploads
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
if ($request->input('redirect_option') === 'back'){
if ($request->get('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
@@ -151,9 +151,7 @@ class UsersController extends Controller
}
if ($request->filled('groups')) {
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
$user->groups()->sync($request->input('groups'));
}
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync([]);
}
@@ -201,7 +199,7 @@ class UsersController extends Controller
}
$permissions = config('permissions');
$groups = Group::orderBy('name', 'asc')->pluck('name', 'id');
$groups = Group::pluck('name', 'id');
$userGroups = $user->groups()->pluck('name', 'id');
$user->permissions = $user->decodePermissions();
@@ -327,7 +325,7 @@ class UsersController extends Controller
// Handle uploaded avatar
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
session()->put(['redirect_option' => $request->input('redirect_option')]);
session()->put(['redirect_option' => $request->get('redirect_option')]);
if ($user->save()) {
// Redirect to the user page
@@ -353,13 +351,10 @@ class UsersController extends Controller
if ($user = User::find($id)) {
$this->authorize('delete', $user);
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
if ($user->delete()) {
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.delete'));
}
if ($user->delete()) {
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.delete'));
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.cannot_delete'));
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found'));
+2 -15
View File
@@ -4,7 +4,6 @@ namespace App\Http\Controllers;
use App\Actions\CheckoutRequests\CancelCheckoutRequestAction;
use App\Actions\CheckoutRequests\CreateCheckoutRequestAction;
use App\Enums\ActionType;
use App\Exceptions\AssetNotRequestable;
use App\Models\Actionlog;
use App\Models\Asset;
@@ -156,19 +155,7 @@ class ViewAssetsController extends Controller
public function getRequestableIndex() : View
{
$assets = Asset::with('model', 'defaultLoc', 'location', 'assignedTo', 'requests')->Hardware()->RequestableAssets();
$models = AssetModel::with([
'category',
'requests',
'assets' => function ($q) {
$q->where('requestable', 1)
->whereHas('assetstatus', fn ($s) =>
$s->where('archived', 0)
->where(fn ($s) =>
$s->where('deployable', 1)->orWhere('pending', 1)
)
);
},
])->RequestableModels()->get();
$models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
return view('account/requestable-assets', compact('assets', 'models'));
}
@@ -214,7 +201,7 @@ class ViewAssetsController extends Controller
if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) {
$item->cancelRequest($requestingUser);
$data['item_quantity'] = ($item_request) ? $item_request->qty : 1;
$logaction->logaction(ActionType::RequestCanceled);
$logaction->logaction('request_canceled');
if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
$settings->notify(new RequestAssetCancelation($data));
-1
View File
@@ -44,7 +44,6 @@ class Kernel extends HttpKernel
\App\Http\Middleware\CheckForTwoFactor::class,
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
\App\Http\Middleware\AssetCountForSidebar::class,
\App\Http\Middleware\CheckColorSettings::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
@@ -1,75 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Models\Setting;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\Facades\Auth;
class CheckColorSettings
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// Set defaults in case this is accessed via the /setup screen
$nav_color = '#ffffff';
$link_dark_color = '#89c9ed';
$link_light_color = '#3c8dbc';
if ($settings = Setting::getSettings()) {
$nav_color = $settings->nav_link_color;
$link_dark_color = $settings->link_dark_color;
$link_light_color = $settings->link_light_color;
}
// Override system settings
if ($request->user()) {
if ($request->user()->nav_color) {
$nav_color = $request->user()->nav_color;
}
if ($request->user()->link_dark_color) {
$link_dark_color = $request->user()->link_dark_color;
}
if ($request->user()->nav_color) {
$link_light_color = $request->user()->link_light_color;
}
}
view()->share('nav_link_color', $nav_color);
view()->share('link_dark_color', $link_dark_color);
view()->share('link_light_color', $link_light_color);
return $next($request);
}
}
@@ -1,68 +0,0 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Traits\MayContainCustomFields;
use App\Models\Asset;
use Illuminate\Foundation\Http\FormRequest;
use App\Helpers\Helper;
use App\Models\Setting;
use App\Models\AssetModel;
use App\Rules\UniqueUndeleted;
use Illuminate\Support\Str;
class CreateMultipleAssetRequest extends ImageUploadRequest //should I extend from StoreAssetRequest? FIXME OR TODO OR THINKME
{
use MayContainCustomFields;
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true; //TODO - should I do the auth check here?
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
//grab the rules for serials and asset_tags, and tweak them into an array context for multi-create usage
$modelRules = (new Asset)->getRules();
unset($modelRules['serial']);
$asset_tag_rules = $modelRules['asset_tag'];
unset($modelRules['asset_tag']);
// now we replace the 'not_array' rule with 'distinct'
array_splice($asset_tag_rules, array_search('not_array', $asset_tag_rules), 1, 'distinct');
// and replace the 'unique_undeleted' rule with the Rule object
foreach ($asset_tag_rules as $i => $asset_tag_rule) {
if (Str::startsWith($asset_tag_rule, 'unique_undeleted')) {
$asset_tag_rules[$i] = new UniqueUndeleted('assets', 'asset_tag');
}
}
$serials_unique = Setting::getSettings()['unique_serial'];
$serials_required = AssetModel::find($this?->model_id)?->require_serial;
$serial_rules = ['string'];
if ($serials_unique) {
// $serial_rules[] = 'unique_undeleted:assets,serial';
$serial_rules[] = new UniqueUndeleted('assets', 'serial');
$serial_rules[] = 'distinct';
}
if ($serials_required) {
$serial_rules[] = 'required';
} else {
$serial_rules[] = 'nullable';
}
return array_merge($modelRules, [
'serials.*' => $serial_rules,
'asset_tags.*' => $asset_tag_rules,
]);
}
}
-29
View File
@@ -1,29 +0,0 @@
<?php
namespace App\Http\Requests;
use App\Rules\ValidJson;
use Illuminate\Foundation\Http\FormRequest;
class FilterRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'filter' => ['nullable', new ValidJson()],
];
}
}
+2 -2
View File
@@ -62,8 +62,8 @@ class ItemImportRequest extends FormRequest
}
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
->setCreatedBy(auth()->id())
->setUpdating($this->input('import-update'))
->setShouldNotify($this->input('send-welcome'))
->setUpdating($this->get('import-update'))
->setShouldNotify($this->get('send-welcome'))
->setUsernameFormat('firstname.lastname')
->setFieldMappings($fieldMappings);
$importer->import();
+1 -1
View File
@@ -44,7 +44,7 @@ class SaveUserRequest extends FormRequest
case 'POST':
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
if ($this->input('ldap_import') == false) {
if ($this->request->get('ldap_import') == false) {
$rules['password'] = Setting::passwordComplexityRulesSaving('store').'|confirmed';
}
break;
+1
View File
@@ -28,6 +28,7 @@ class SetupUserRequest extends Request
'username' => 'required|string|min:2|unique:users,username,NULL,deleted_at',
'email' => 'email|unique:users,email',
'password' => 'required|min:8|confirmed',
'email_domain' => 'required|min:4',
];
}
@@ -19,7 +19,6 @@ class StoreAccessoryRequest extends ImageUploadRequest
public function prepareForValidation(): void
{
parent::prepareForValidation();
if ($this->category_id) {
if ($category = Category::find($this->category_id)) {
@@ -19,7 +19,6 @@ class StoreConsumableRequest extends ImageUploadRequest
public function prepareForValidation(): void
{
parent::prepareForValidation();
if ($this->category_id) {
if ($category = Category::find($this->category_id)) {
@@ -1,32 +0,0 @@
<?php
namespace App\Http\Requests;
use App\Models\Department;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreDepartmentRequest extends ImageUploadRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('create', new Department);
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$modelRules = (new Department)->getRules();
return array_merge(
$modelRules,
);
}
}

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