Compare commits

..

32 Commits

Author SHA1 Message Date
snipe
750c376725 Set item to null so it doesn’t get merged automatically 2025-09-29 13:29:00 +01:00
snipe
08630d948f Remove radio buttons - they don’t work correctly yet 2025-09-29 12:43:19 +01:00
snipe
dc6ee342c5 Revert custom field name text box for now 2025-09-29 10:42:40 +01:00
snipe
eea1922841 Added checkbox and radios 2025-09-25 13:22:52 +01:00
snipe
57824848e9 Update resources/views/blade/form-row.blade.php
Co-authored-by: Marcus Moore <mmoore@grokability.com>
2025-09-24 17:08:00 +01:00
snipe
235dcbc7d9 Updated more views 2025-09-24 16:58:35 +01:00
snipe
f0561475cc Update resources/views/blade/input/text.blade.php
Co-authored-by: Marcus Moore <mmoore@grokability.com>
2025-09-24 16:41:56 +01:00
snipe
3b4c51bab6 Use slot instead of label 2025-09-24 14:52:29 +01:00
snipe
150c205615 Added checkboxes to status labels page 2025-09-23 21:37:17 +01:00
snipe
cde22977b0 More checkbox changes 2025-09-23 21:23:03 +01:00
snipe
1c09657631 Handle checkboxes 2025-09-23 20:57:33 +01:00
snipe
02a4268180 Switched more fields to blade compaonents 2025-09-23 19:52:58 +01:00
snipe
f8362f4a45 handled text fields in status labels 2025-09-23 18:44:06 +01:00
snipe
682c1a8fa7 Make required false 2025-09-23 18:43:50 +01:00
snipe
3863e82dcc Handle text and date fields on license edit 2025-09-23 18:43:39 +01:00
snipe
b766f6e2b5 Made edit screen narrower on wide screens 2025-09-23 18:43:14 +01:00
snipe
a3bad98096 Added date and tooltip components 2025-09-23 18:43:02 +01:00
snipe
33e7425dee Account for tooltips 2025-09-23 18:42:46 +01:00
snipe
2554b50b38 Updated suppliers 2025-09-23 17:04:49 +01:00
snipe
433a3e11fd Fixed field type 2025-09-23 17:00:03 +01:00
snipe
c3efdd0c8d Updated company 2025-09-23 16:59:09 +01:00
snipe
d2e3a13043 Added ability to mark fields as disabled 2025-09-23 16:58:53 +01:00
snipe
c4923fa971 Updated address 2025-09-23 16:53:52 +01:00
snipe
253026de5d Updated locations edit 2025-09-23 16:51:55 +01:00
snipe
a59914e9f9 Added placeholder back in 2025-09-23 16:38:12 +01:00
snipe
671e79f01b Sorry, this shouldn’t have been in there :( 2025-09-23 16:35:04 +01:00
snipe
5c716c3f24 Updated notes maxlength 2025-09-23 16:31:20 +01:00
snipe
e138c9307e Added maxlength default for text 2025-09-23 16:30:18 +01:00
snipe
7c0c3b2bb8 Use shorthand for errors 2025-09-23 16:26:28 +01:00
snipe
514711ddbb Label blade component 2025-09-23 16:18:00 +01:00
snipe
9023eda66f Changed class 2025-09-23 14:25:52 +01:00
snipe
8ce3001ef9 First stab 2025-09-23 14:25:40 +01:00
1997 changed files with 10855 additions and 54350 deletions

View File

@@ -4235,33 +4235,6 @@
"contributions": [ "contributions": [
"code" "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"
]
} }
] ]
} }

View File

@@ -137,8 +137,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null PUBLIC_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------
@@ -149,8 +147,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null PRIVATE_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------

View File

@@ -144,8 +144,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null PUBLIC_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------
@@ -156,8 +154,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null PRIVATE_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------

View File

@@ -143,8 +143,6 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
PUBLIC_AWS_DEFAULT_REGION=null PUBLIC_AWS_DEFAULT_REGION=null
PUBLIC_AWS_BUCKET=null PUBLIC_AWS_BUCKET=null
PUBLIC_AWS_URL=null PUBLIC_AWS_URL=null
PUBLIC_AWS_ENDPOINT=null
PUBLIC_AWS_PATH_STYLE=null
PUBLIC_AWS_BUCKET_ROOT=null PUBLIC_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------
@@ -155,8 +153,6 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
PRIVATE_AWS_DEFAULT_REGION=null PRIVATE_AWS_DEFAULT_REGION=null
PRIVATE_AWS_BUCKET=null PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null PRIVATE_AWS_URL=null
PRIVATE_AWS_ENDPOINT=null
PRIVATE_AWS_PATH_STYLE=null
PRIVATE_AWS_BUCKET_ROOT=null PRIVATE_AWS_BUCKET_ROOT=null
# -------------------------------------------- # --------------------------------------------
@@ -194,14 +190,13 @@ APP_ALLOW_INSECURE_HOSTS=false
GOOGLE_MAPS_API= GOOGLE_MAPS_API=
LDAP_MEM_LIM=500M LDAP_MEM_LIM=500M
LDAP_TIME_LIM=600 LDAP_TIME_LIM=600
BACKUP_TIME_LIMIT=600
IMPORT_TIME_LIMIT=600 IMPORT_TIME_LIMIT=600
IMPORT_MEMORY_LIMIT=500M IMPORT_MEMORY_LIMIT=500M
REPORT_TIME_LIMIT=12000 REPORT_TIME_LIMIT=12000
API_THROTTLE_PER_MINUTE=120 API_THROTTLE_PER_MINUTE=120
CSV_ESCAPE_FORMULAS=true CSV_ESCAPE_FORMULAS=true
LIVEWIRE_URL_PREFIX=null LIVEWIRE_URL_PREFIX=null
MAX_UNPAGINATED=5000
# -------------------------------------------- # --------------------------------------------
# OPTIONAL: SAML SETTINGS # OPTIONAL: SAML SETTINGS

View File

@@ -23,23 +23,7 @@ body:
attributes: attributes:
label: Snipe-IT Version label: Snipe-IT Version
description: What version of Snipe-IT are you seeing this issue on? You can find the version number in the footer of any page in Snipe-IT. description: What version of Snipe-IT are you seeing this issue on? You can find the version number in the footer of any page in Snipe-IT.
placeholder: ex. v8.3.2 - build 19577 (master) placeholder: ex. v8.3.1 - build 19577 (master)
validations:
required: true
- type: input
id: php-version
attributes:
label: PHP Version
description: What version of PHP are you running? You can find the version of PHP your webserver is running in the `Admin Settings` section in the footer, and the cli version by running `php -v` via command line .
placeholder: ex. v8.3.1 (web), PHP 8.4.12 (cli)
validations:
required: true
- type: input
id: composer-version
attributes:
label: Composer Version
description: What version of composer are you running? You can find the version number by running `composer --version`.
placeholder: ex. 2.8.10
validations: validations:
required: true required: true
- type: input - type: input
@@ -64,16 +48,6 @@ body:
- Not sure - Not sure
validations: validations:
required: true required: true
- type: dropdown
id: upgrade-or-fresh
attributes:
label: Is this a fresh install or an upgrade?
options:
- Fresh install
- Upgrade
- NA
validations:
required: true
- type: textarea - type: textarea
id: what-happened id: what-happened
attributes: attributes:
@@ -160,4 +134,4 @@ body:
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md). description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md).
options: options:
- label: I agree to follow this project's Code of Conduct - label: I agree to follow this project's Code of Conduct
required: true required: true

View File

@@ -26,14 +26,14 @@ jobs:
language: [ 'javascript' ] language: [ 'javascript' ]
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v5
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v4 uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4 uses: github/codeql-action/analyze@v3

View File

@@ -32,7 +32,7 @@ jobs:
steps: steps:
# Checkout the repository to the GitHub Actions runner # Checkout the repository to the GitHub Actions runner
- name: Checkout code - 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 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI - name: Run Codacy Analysis CLI
@@ -52,6 +52,6 @@ jobs:
# Upload the SARIF file generated in the previous step # Upload the SARIF file generated in the previous step
- name: Upload SARIF results file - name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v4 uses: github/codeql-action/upload-sarif@v3
with: with:
sarif_file: results.sarif sarif_file: results.sarif

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Crowdin push - name: Crowdin push
uses: crowdin/github-action@v2 uses: crowdin/github-action@v2

View File

@@ -42,7 +42,7 @@ jobs:
steps: steps:
# https://github.com/actions/checkout # https://github.com/actions/checkout
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v6 uses: actions/checkout@v5
# https://github.com/docker/setup-buildx-action # https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx - name: Setup Docker Buildx

View File

@@ -42,7 +42,7 @@ jobs:
steps: steps:
# https://github.com/actions/checkout # https://github.com/actions/checkout
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v6 uses: actions/checkout@v5
# https://github.com/docker/setup-buildx-action # https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx - name: Setup Docker Buildx

View File

@@ -11,7 +11,7 @@ jobs:
dockerHubDescription: dockerHubDescription:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v5
- name: Docker Hub Description - name: Docker Hub Description
uses: grokability/dockerhub-description@7ea9d275c7cdbe2b676a093a0308c50665e3b8b4 uses: grokability/dockerhub-description@7ea9d275c7cdbe2b676a093a0308c50665e3b8b4

View File

@@ -37,7 +37,7 @@ jobs:
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-version }}"
coverage: none coverage: none
- uses: actions/checkout@v6 - uses: actions/checkout@v5
- name: Get Composer Cache Directory - name: Get Composer Cache Directory
id: composer-cache id: composer-cache
@@ -82,7 +82,7 @@ jobs:
- name: Upload Laravel logs as artifacts - name: Upload Laravel logs as artifacts
if: always() if: always()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: | path: |

View File

@@ -34,7 +34,7 @@ jobs:
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-version }}"
coverage: none coverage: none
- uses: actions/checkout@v6 - uses: actions/checkout@v5
- name: Get Composer Cache Directory - name: Get Composer Cache Directory
id: composer-cache id: composer-cache
@@ -81,7 +81,7 @@ jobs:
- name: Upload Laravel logs as artifacts - name: Upload Laravel logs as artifacts
if: always() if: always()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: | path: |

View File

@@ -25,7 +25,7 @@ jobs:
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-version }}"
coverage: none coverage: none
- uses: actions/checkout@v6 - uses: actions/checkout@v5
- name: Get Composer Cache Directory - name: Get Composer Cache Directory
id: composer-cache id: composer-cache
@@ -67,7 +67,7 @@ jobs:
- name: Upload Laravel logs as artifacts - name: Upload Laravel logs as artifacts
if: always() if: always()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: | path: |

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/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/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/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/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/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") |
<!-- ALL-CONTRIBUTORS-LIST:END --> <!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -83,7 +83,6 @@ Since the release of the JSON REST API, several third-party developers have been
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance - [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 - [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) - [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. - [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 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. - [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.

View File

@@ -1,59 +0,0 @@
<?php
namespace App\Actions\Categories;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssetModels;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Models\Category;
use Illuminate\Support\Facades\Storage;
class DestroyCategoryAction
{
/**
* @throws ItemStillHasAssets
* @throws ItemStillHasAssetModels
* @throws ItemStillHasComponents
* @throws ItemStillHasAccessories
* @throws ItemStillHasLicenses
* @throws ItemStillHasConsumables
*/
static function run(Category $category): bool
{
$category->loadCount([
'assets as assets_count',
'accessories as accessories_count',
'consumables as consumables_count',
'components as components_count',
'licenses as licenses_count',
'models as models_count'
]);
if ($category->assets_count > 0) {
throw new ItemStillHasAssets($category);
}
if ($category->accessories_count > 0) {
throw new ItemStillHasAccessories($category);
}
if ($category->consumables_count > 0) {
throw new ItemStillHasConsumables($category);
}
if ($category->components_count > 0) {
throw new ItemStillHasComponents($category);
}
if ($category->licenses_count > 0) {
throw new ItemStillHasLicenses($category);
}
if ($category->models_count > 0) {
throw new ItemStillHasAssetModels($category);
}
Storage::disk('public')->delete('categories'.'/'.$category->image);
$category->delete();
return true;
}
}

View File

@@ -1,63 +0,0 @@
<?php
namespace App\Actions\Manufacturers;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Models\Manufacturer;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class DeleteManufacturerAction
{
/**
* @throws ItemStillHasAssets
* @throws ItemStillHasComponents
* @throws ItemStillHasAccessories
* @throws ItemStillHasLicenses
* @throws ItemStillHasConsumables
*/
static function run(Manufacturer $manufacturer): bool
{
$manufacturer->loadCount([
'assets as assets_count',
'accessories as accessories_count',
'consumables as consumables_count',
'components as components_count',
'licenses as licenses_count',
]);
if ($manufacturer->assets_count > 0) {
throw new ItemStillHasAssets($manufacturer);
}
if ($manufacturer->accessories_count > 0) {
throw new ItemStillHasAccessories($manufacturer);
}
if ($manufacturer->consumables_count > 0) {
throw new ItemStillHasConsumables($manufacturer);
}
if ($manufacturer->components_count > 0) {
throw new ItemStillHasComponents($manufacturer);
}
if ($manufacturer->licenses_count > 0) {
throw new ItemStillHasLicenses($manufacturer);
}
if ($manufacturer->image) {
try {
Storage::disk('public')->delete('manufacturers/'.$manufacturer->image);
} catch (\Exception $e) {
Log::info($e);
}
}
$manufacturer->delete();
//dd($manufacturer);
return true;
}
}

View File

@@ -1,72 +0,0 @@
<?php
namespace App\Actions\Suppliers;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Models\Supplier;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasMaintenances;
use App\Exceptions\ItemStillHasLicenses;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class DestroySupplierAction
{
/**
*
* @throws ItemStillHasLicenses
* @throws ItemStillHasAssets
* @throws ItemStillHasMaintenances
* @throws ItemStillHasAccessories
* @throws ItemStillHasConsumables
* @throws ItemStillHasComponents
*/
static function run(Supplier $supplier): bool
{
$supplier->loadCount([
'maintenances as maintenances_count',
'assets as assets_count',
'licenses as licenses_count',
'accessories as accessories_count',
'consumables as consumables_count',
'components as components_count',
]);
if ($supplier->assets_count > 0) {
throw new ItemStillHasAssets($supplier);
}
if ($supplier->maintenances_count > 0) {
throw new ItemStillHasMaintenances($supplier);
}
if ($supplier->licenses_count > 0) {
throw new ItemStillHasLicenses($supplier);
}
if ($supplier->accessories_count > 0) {
throw new ItemStillHasAccessories($supplier);
}
if ($supplier->consumables_count > 0) {
throw new ItemStillHasConsumables($supplier);
}
if ($supplier->components_count > 0) {
throw new ItemStillHasComponents($supplier);
}
if ($supplier->image) {
try {
Storage::disk('public')->delete('suppliers/'.$supplier->image);
} catch (\Exception $e) {
Log::info($e->getMessage());
}
}
$supplier->delete();
return true;
}
}

View File

@@ -317,21 +317,9 @@ class LdapSync extends Command
if($ldap_map["jobtitle"] != null){ if($ldap_map["jobtitle"] != null){
$user->jobtitle = $item['jobtitle']; $user->jobtitle = $item['jobtitle'];
} }
if($ldap_map["address"] != null){
$user->address = $item['address'];
}
if($ldap_map["city"] != null){
$user->city = $item['city'];
}
if($ldap_map["state"] != null){
$user->state = $item['state'];
}
if($ldap_map["country"] != null){ if($ldap_map["country"] != null){
$user->country = $item['country']; $user->country = $item['country'];
} }
if($ldap_map["zip"] != null){
$user->zip = $item['zip'];
}
if($ldap_map["dept"] != null){ if($ldap_map["dept"] != null){
$user->department_id = $department->id; $user->department_id = $department->id;
} }

View File

@@ -8,6 +8,8 @@ use Symfony\Component\Console\Input\InputOption;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Symfony\Component\Console\Helper\ProgressIndicator; use Symfony\Component\Console\Helper\ProgressIndicator;
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
/** /**
* Class ObjectImportCommand * Class ObjectImportCommand
@@ -50,9 +52,6 @@ class ObjectImportCommand extends Command
*/ */
public function handle() public function handle()
{ {
ini_set('max_execution_time', env('IMPORT_TIME_LIMIT', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('IMPORT_MEMORY_LIMIT', '500M'));
$this->progressIndicator = new ProgressIndicator($this->output); $this->progressIndicator = new ProgressIndicator($this->output);
$filename = $this->argument('filename'); $filename = $this->argument('filename');

View File

@@ -1,56 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Models\Actionlog;
use Illuminate\Console\Command;
class RemoveInvalidUploadDeleteActionLogItems extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:remove-invalid-upload-delete-action-log-items';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Permanently remove invalid "upload deleted" action log items that have a null filename. This command can potentially result in deleted files being "resurrected" in the UI.';
/**
* Execute the console command.
*/
public function handle()
{
$invalidLogs = Actionlog::query()
->where('action_type', 'upload deleted')
->whereNull('filename')
->withTrashed()
->get();
$this->info("{$invalidLogs->count()} invalid log items found.");
if ($invalidLogs->count() === 0) {
return 0;
}
$this->table(['ID', 'Action Type', 'Item Type', 'Item ID', 'Created At', 'Deleted At'], $invalidLogs->map(fn($log) => [
$log->id,
$log->action_type,
$log->item_type,
$log->item_id,
$log->created_at,
$log->deleted_at,
])->toArray());
if ($this->confirm("Do you wish to remove {$invalidLogs->count()} log items?")) {
$invalidLogs->each(fn($log) => $log->forceDelete());
}
return 0;
}
}

View File

@@ -5,7 +5,6 @@ namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use ZipArchive; use ZipArchive;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use enshrined\svgSanitize\Sanitizer;
class SQLStreamer { class SQLStreamer {
private $input; private $input;
@@ -243,10 +242,9 @@ class RestoreFromBackup extends Command
$private_dirs = [ $private_dirs = [
'storage/private_uploads/accessories', 'storage/private_uploads/accessories',
'storage/private_uploads/assetmodels' => 'storage/private_uploads/models', //this was changed from assetmodels => models Aug 10 2025 'storage/private_uploads/assetmodels',
'storage/private_uploads/asset_maintenances' => 'storage/private_uploads/maintenances', //this was changed from asset_maintenances => maintenances Aug 10 2025 'storage/private_uploads/maintenances',
'storage/private_uploads/maintenances', //but let 'maintenances' take precedence 'storage/private_uploads/models',
'storage/private_uploads/models', //and let 'models' take precedence
'storage/private_uploads/assets', // these are asset _files_, not the pictures. 'storage/private_uploads/assets', // these are asset _files_, not the pictures.
'storage/private_uploads/audits', 'storage/private_uploads/audits',
'storage/private_uploads/components', 'storage/private_uploads/components',
@@ -264,7 +262,7 @@ class RestoreFromBackup extends Command
]; ];
$public_dirs = [ $public_dirs = [
'public/uploads/accessories', 'public/uploads/accessories',
// 'public/uploads/assetmodels' => 'public/uploads/models', //according to git, this was _never_ a thing... (see below) 'public/uploads/assetmodels',
'public/uploads/maintenances', 'public/uploads/maintenances',
'public/uploads/assets', // these are asset _pictures_, not asset files 'public/uploads/assets', // these are asset _pictures_, not asset files
'public/uploads/avatars', 'public/uploads/avatars',
@@ -275,7 +273,7 @@ class RestoreFromBackup extends Command
'public/uploads/departments', 'public/uploads/departments',
'public/uploads/locations', 'public/uploads/locations',
'public/uploads/manufacturers', 'public/uploads/manufacturers',
'public/uploads/models', // ...it's been this way for 9 years (as of late 2025) 'public/uploads/models',
'public/uploads/suppliers', 'public/uploads/suppliers',
]; ];
@@ -288,6 +286,8 @@ class RestoreFromBackup extends Command
'public/uploads/favicon-uploaded.*', 'public/uploads/favicon-uploaded.*',
]; ];
$all_files = $private_dirs + $public_dirs;
$sqlfiles = []; $sqlfiles = [];
$sqlfile_indices = []; $sqlfile_indices = [];
@@ -295,20 +295,6 @@ class RestoreFromBackup extends Command
$boring_files = []; $boring_files = [];
$unsafe_files = []; $unsafe_files = [];
$good_extensions = config('filesystems.allowed_upload_extensions_array');
$private_extensions = array_merge($good_extensions, ["csv", "key"]); //add csv, and 'key'
$public_extensions = array_diff($good_extensions, ["xml"]); //remove xml
$sanitizer = new Sanitizer();
/**
* TODO: I _hate_ the "continue 3" thing we keep doing here
* I think a better approach might be to have the "each file" stuff be in a method on this class, and the
* boring_files and interesting_files be properties on it that we fill out. Then, in that method, we could
* just do a 'return' once the file is actually handled (yay or nay). We could also start to break out some of
* the _other_ things that we do into their own methods too? But I don't care about that as much.
*/
for ($i = 0; $i < $za->numFiles; $i++) { for ($i = 0; $i < $za->numFiles; $i++) {
$stat_results = $za->statIndex($i); $stat_results = $za->statIndex($i);
// echo "index: $i\n"; // echo "index: $i\n";
@@ -323,7 +309,7 @@ class RestoreFromBackup extends Command
// skip macOS resource fork files (?!?!?!) // skip macOS resource fork files (?!?!?!)
if (strpos($raw_path, '__MACOSX') !== false && strpos($raw_path, '._') !== false) { if (strpos($raw_path, '__MACOSX') !== false && strpos($raw_path, '._') !== false) {
//print "SKIPPING macOS Resource fork file: $raw_path\n"; //print "SKIPPING macOS Resource fork file: $raw_path\n";
// $boring_files[] = $raw_path; //stop adding this to the boring files list; it's just confusing $boring_files[] = $raw_path;
continue; continue;
} }
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') { if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
@@ -332,70 +318,44 @@ class RestoreFromBackup extends Command
$sqlfile_indices[] = $i; $sqlfile_indices[] = $i;
continue; continue;
} }
if ($raw_path[-1] == '/') {
//last character is '/' - this is a directory, and we don't need it, and we don't need to warn about it
continue;
}
if (in_array(basename($raw_path), [".gitkeep", ".gitignore", ".DS_Store"])) {
//skip these boring files silently without reporting on them; they're stupid
continue;
}
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
foreach (['public' => $public_dirs, 'private' => $private_dirs] as $purpose => $dirs) { foreach (array_merge($private_dirs, $public_dirs) as $dir) {
$allowed_extensions = match ($purpose) { $last_pos = strrpos($raw_path, $dir . '/');
'public' => $public_extensions, if ($last_pos !== false) {
'private' => $private_extensions, //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
}; //print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
foreach ($dirs as $dir => $destdir) { $interesting_files[$raw_path] = ['dest' => $dir, 'index' => $i];
if (is_int($dir)) { continue 2;
$dir = $destdir; if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) {
} // we don't care about that; we just want files with the appropriate prefix
$last_pos = strrpos($raw_path, $dir . '/'); //print("FOUND THE EXACT DIRECTORY: $dir AT: $raw_path!!!\n");
if ($last_pos !== false) {
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
//the CSV bit, below, is because we store CSV files as "blahcsv" - without an extension
if (!in_array($extension, $allowed_extensions) && !($dir == "storage/private_uploads/imports" && substr($raw_path, -3) == "csv" && $extension == "")) {
$unsafe_files[] = $raw_path;
Log::debug($raw_path . ' from directory ' . $dir . ' is being skipped');
} else {
if ($dir != $destdir) {
Log::debug("Getting ready to save file $raw_path to new directory $destdir");
}
$interesting_files[$raw_path] = ['dest' => $destdir, 'index' => $i];
}
continue 3;
} }
} }
} }
foreach (['public' => $public_files, 'private' => $private_files] as $purpose => $files) { $good_extensions = config('filesystems.allowed_upload_extensions_array');
$allowed_extensions = match ($purpose) {
'public' => $public_extensions, foreach (array_merge($private_files, $public_files) as $file) {
'private' => $private_extensions, $has_wildcard = (strpos($file, '*') !== false);
}; if ($has_wildcard) {
foreach ($files as $file) { $file = substr($file, 0, -1); //trim last character (which should be the wildcard)
$has_wildcard = (strpos($file, '*') !== false); }
if ($has_wildcard) { $last_pos = strrpos($raw_path, $file); // no trailing slash!
$file = substr($file, 0, -1); //trim last character (which should be the wildcard) if ($last_pos !== false) {
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
if (!in_array($extension, $good_extensions)) {
// gathering potentially unsafe files here to return at exit
$unsafe_files[] = $raw_path;
Log::debug('Potentially unsafe file '.$raw_path.' is being skipped');
$boring_files[] = $raw_path;
continue 2;
} }
$last_pos = strrpos($raw_path, $file); // no trailing slash! //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
if ($last_pos !== false) { //no wildcards found in $file, process 'normally'
if (!in_array($extension, $allowed_extensions)) { if ($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it.
// gathering potentially unsafe files here to return at exit // print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though.
$unsafe_files[] = $raw_path; $interesting_files[$raw_path] = ['dest' => dirname($file), 'index' => $i];
Log::debug('Potentially unsafe file ' . $raw_path . ' is being skipped'); continue 2;
$boring_files[] = $raw_path;
continue 3;
}
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
//no wildcards found in $file, process 'normally'
if ($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it.
// print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though.
$interesting_files[$raw_path] = ['dest' => dirname($file), 'index' => $i];
continue 3;
}
} }
} }
} }
@@ -532,25 +492,18 @@ class RestoreFromBackup extends Command
} }
foreach ($interesting_files as $pretty_file_name => $file_details) { foreach ($interesting_files as $pretty_file_name => $file_details) {
$ugly_file_name = $za->statIndex($file_details['index'])['name']; $ugly_file_name = $za->statIndex($file_details['index'])['name'];
$migrated_file_name = $file_details['dest'] . '/' . basename($pretty_file_name); $fp = $za->getStream($ugly_file_name);
if (strcasecmp(substr($pretty_file_name, -4), ".svg") === 0) { //$this->info("Weird problem, here are file details? ".print_r($file_details,true));
$svg_contents = $za->getFromIndex($file_details['index']); if (!is_dir($file_details['dest'])) {
$cleaned_svg = $sanitizer->sanitize($svg_contents); mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that
file_put_contents($migrated_file_name, $cleaned_svg);
} else {
$fp = $za->getStream($ugly_file_name);
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
if (!is_dir($file_details['dest'])) {
mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that
}
$migrated_file = fopen($migrated_file_name, 'w');
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
fwrite($migrated_file, $buffer);
}
fclose($migrated_file);
fclose($fp);
//$this->info("Wrote $ugly_file_name to $pretty_file_name");
} }
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
fwrite($migrated_file, $buffer);
}
fclose($migrated_file);
fclose($fp);
//$this->info("Wrote $ugly_file_name to $pretty_file_name");
if ($bar) { if ($bar) {
$bar->advance(); $bar->advance();
} }

View File

@@ -3,18 +3,13 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Mail\UnacceptedAssetReminderMail; use App\Mail\UnacceptedAssetReminderMail;
use App\Models\Accessory;
use App\Models\Asset; use App\Models\Asset;
use App\Models\CheckoutAcceptance; use App\Models\CheckoutAcceptance;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\Notifications\CheckoutAssetNotification; use App\Notifications\CheckoutAssetNotification;
use App\Notifications\CurrentInventory; use App\Notifications\CurrentInventory;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
class SendAcceptanceReminder extends Command class SendAcceptanceReminder extends Command
@@ -31,7 +26,7 @@ class SendAcceptanceReminder extends Command
* *
* @var string * @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. * Create a new command instance.
@@ -50,30 +45,19 @@ class SendAcceptanceReminder extends Command
*/ */
public function handle() public function handle()
{ {
$pending = CheckoutAcceptance::query() $pending = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')
->with([ ->whereHas('checkoutable', function($query) {
'checkoutable' => function (MorphTo $morph) { $query->where('accepted_at', null)
$morph->morphWith([ ->where('declined_at', null);
Asset::class => ['model.category', 'assignedTo', 'adminuser', 'company', 'checkouts'], })
Accessory::class => ['category', 'company', 'checkouts'], ->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model', 'checkoutable.adminuser'])
LicenseSeat::class => ['user', 'license', 'checkouts'], ->get();
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();
$count = 0; $count = 0;
$unacceptedAssetGroups = $pending $unacceptedAssetGroups = $pending
->filter(function($acceptance) {
return $acceptance->checkoutable_type == 'App\Models\Asset';
})
->map(function($acceptance) { ->map(function($acceptance) {
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance]; return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
}) })

View File

@@ -9,8 +9,6 @@ use App\Notifications\ExpectedCheckinAdminNotification;
use App\Notifications\ExpectedCheckinNotification; use App\Notifications\ExpectedCheckinNotification;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;
use App\Helpers\Helper;
class SendExpectedCheckinAlerts extends Command class SendExpectedCheckinAlerts extends Command
{ {
@@ -19,7 +17,7 @@ class SendExpectedCheckinAlerts extends Command
* *
* @var string * @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. * The console command description.
@@ -44,47 +42,19 @@ class SendExpectedCheckinAlerts extends Command
public function handle() public function handle()
{ {
$settings = Setting::getSettings(); $settings = Setting::getSettings();
$interval = $settings->due_checkin_days ?? 0; $interval = $settings->audit_warning_days ?? 0;
$today = Carbon::now(); $today = Carbon::now();
$interval_date = $today->copy()->addDays($interval); $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(); $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) { foreach ($assets as $asset) {
if ($asset->assignedTo && (isset($asset->assignedTo->email)) && ($asset->assignedTo->email!='') && $asset->checkedOutToUser()) { 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))); $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) { $recipients = collect(explode(',', $settings->alert_email))->map(function ($item) {
return new AlertRecipient($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.');
} }
} }

View File

@@ -60,57 +60,19 @@ class SendExpirationAlerts extends Command
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval)); Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
$this->table( $this->table(
[ ['ID', 'Tag', 'Model', 'Model Number', 'EOL', 'EOL Months', 'Warranty Expires', 'Warranty Months'],
trans('general.id'), $assets->map(fn($item) => ['ID' => $item->id, 'Tag' => $item->asset_tag, 'Model' => $item->model->name, 'Model Number' => $item->model->model_number, 'EOL' => $item->asset_eol_date, 'EOL Months' => $item->model->eol, 'Warranty Expires' => $item->warranty_expires, 'Warranty Months' => $item->warranty_months])
trans('admin/hardware/form.tag'), );
trans('admin/hardware/form.model'),
trans('general.model_no'),
trans('general.purchase_date'),
trans('admin/hardware/form.eol_rate'),
trans('admin/hardware/form.eol_date'),
trans('admin/hardware/form.warranty_expires'),
],
$assets->map(fn($item) =>
[
trans('general.id') => $item->id,
trans('admin/hardware/form.tag') => $item->asset_tag,
trans('admin/hardware/form.model') => $item->model->name,
trans('general.model_no') => $item->model->model_number,
trans('general.purchase_date') => $item->purchase_date_formatted,
trans('admin/hardware/form.eol_rate') => $item->model->eol,
trans('admin/hardware/form.eol_date') => $item->eol_date ? $item->eol_formatted_date .' ('.$item->eol_diff_for_humans.')' : '',
trans('admin/hardware/form.warranty_expires') => $item->warranty_expires ? $item->warranty_expires_formatted_date .' ('.$item->warranty_expires_diff_for_humans.')' : '',
])
);
} }
// Expiring licenses // Expiring licenses
$licenses = License::query()->ExpiringLicenses($alert_interval) $licenses = License::getExpiringLicenses($alert_interval);
->with('manufacturer','category')
->orderBy('expiration_date', 'ASC')
->orderBy('termination_date', 'ASC')
->get();
if ($licenses->count() > 0) { if ($licenses->count() > 0) {
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval)); Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval));
$this->table( $this->table(
[ ['ID', 'Name', 'Expires', 'Termination Date'],
trans('general.id'), $licenses->map(fn($item) => ['ID' => $item->id, 'Name' => $item->name, 'Expires' => $item->expiration_date, 'Termination Date' => $item->termination_date])
trans('general.name'),
trans('general.purchase_date'),
trans('admin/licenses/form.expiration'),
trans('mail.expires'),
trans('admin/licenses/form.termination_date'),
trans('mail.terminates')],
$licenses->map(fn($item) => [
trans('general.id') => $item->id,
trans('general.name') => $item->name,
trans('general.purchase_date') => $item->purchase_date_formatted,
trans('admin/licenses/form.expiration') => $item->expires_formatted_date,
trans('mail.expires') => $item->expires_formatted_date ? $item->expires_diff_for_humans : '',
trans('admin/licenses/form.termination_date') => $item->terminates_formatted_date,
trans('mail.terminates') => $item->terminates_diff_for_humans
])
); );
} }

View File

@@ -52,9 +52,7 @@ class SendInventoryAlerts extends Command
return new AlertRecipient($item); return new AlertRecipient($item);
}); });
Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold)); \Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
} else {
$this->info('No low inventory items found. No mail sent.');
} }
} else { } else {
if ($settings->alert_email == '') { if ($settings->alert_email == '') {

View File

@@ -16,7 +16,7 @@ class SendUpcomingAuditReport extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'snipeit:upcoming-audits {--with-output : Display the results in a table in your console in addition to sending the email}'; protected $signature = 'snipeit:upcoming-audits';
/** /**
* The console command description. * The console command description.
@@ -47,69 +47,21 @@ class SendUpcomingAuditReport extends Command
$today = Carbon::now(); $today = Carbon::now();
$interval_date = $today->copy()->addDays($interval); $interval_date = $today->copy()->addDays($interval);
$assets_query = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'asc')->with('supplier'); $assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get();
$asset_count = $assets_query->count(); $this->info($assets->count() . ' assets must be audited in on or before ' . $interval_date . ' is deadline');
$this->info(number_format($asset_count) . ' assets must be audited on or before ' . $interval_date);
if (!$this->option('with-output')) {
$this->info('Run this command with the --with-output option to see the full list in the console.');
}
if ($asset_count > 0) { if ((count($assets) !== 0) && ($assets->count() > 0) && ($settings->alert_email != '')) {
$assets_for_email = $assets_query->limit(30)->get();
// Send a rollup to the admin, if settings dictate // Send a rollup to the admin, if settings dictate
if ($settings->alert_email != '') { $recipients = collect(explode(',', $settings->alert_email))
->map(fn($item) => trim($item))
$recipients = collect(explode(',', $settings->alert_email)) ->filter(fn($item) => !empty($item))
->map(fn($item) => trim($item)) ->all();
->filter(fn($item) => !empty($item))
->all();
Mail::to($recipients)->send(new SendUpcomingAuditMail($assets_for_email, $settings->audit_warning_days, $asset_count));
$this->info('Audit notification sent to: ' . $settings->alert_email);
} else {
$this->info('There is no admin alert email set so no email will be sent.');
}
$this->info('Sending Admin SendUpcomingAuditNotification to: ' . $settings->alert_email);
if ($this->option('with-output')) { Mail::to($recipients)->send(new SendUpcomingAuditMail($assets, $settings->audit_warning_days));
// Get the full list if the user wants output in the console
$assets_for_output = $assets_query->limit(null)->get();
$this->table(
[
trans('general.id'),
trans('general.name'),
trans('general.last_audit'),
trans('general.next_audit_date'),
trans('mail.Days'),
trans('mail.supplier'),
trans('mail.assigned_to'),
],
$assets_for_output->map(fn($item) => [
trans('general.id') => $item->id,
trans('general.name') => $item->display_name,
trans('general.last_audit') => $item->last_audit_formatted_date,
trans('general.next_audit_date') => $item->next_audit_formatted_date,
trans('mail.Days') => round($item->next_audit_diff_in_days),
trans('mail.supplier') => $item->supplier ? $item->supplier->name : '',
trans('mail.assigned_to') => $item->assignedTo ? $item->assignedTo->display_name : '',
])
);
}
} else {
$this->info('There are no assets due for audit in the next ' . $interval . ' days.');
} }
} }
} }

View File

@@ -37,8 +37,6 @@ class SystemBackup extends Command
*/ */
public function handle() public function handle()
{ {
ini_set('max_execution_time', env('BACKUP_TIME_LIMIT', 600)); //600 seconds = 10 minutes
if ($this->option('filename')) { if ($this->option('filename')) {
$filename = $this->option('filename'); $filename = $this->option('filename');

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

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasAccessories extends ItemStillHasChildren
{
//
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasAssetModels extends ItemStillHasChildren
{
//
}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasAssets extends ItemStillHasChildren
{
}

View File

@@ -1,14 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasChildren extends Exception
{
//public function __construct($message, $code = 0, Exception $previous = null, $parent, $children)
//{
// trans()
//
//}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasComponents extends ItemStillHasChildren
{
//
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasConsumables extends ItemStillHasChildren
{
//
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasLicenses extends ItemStillHasChildren
{
//
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\Exceptions;
use Exception;
class ItemStillHasMaintenances extends ItemStillHasChildren
{
//
}

View File

@@ -40,8 +40,6 @@ class IconHelper
return 'fa-solid fa-trash-arrow-up'; return 'fa-solid fa-trash-arrow-up';
case 'external-link': case 'external-link':
return 'fa fa-external-link'; return 'fa fa-external-link';
case 'link':
return 'fa fa-link';
case 'email': case 'email':
return 'fa-regular fa-envelope'; return 'fa-regular fa-envelope';
case 'phone': case 'phone':
@@ -197,10 +195,6 @@ class IconHelper
case 'note': case 'note':
case 'notes': case 'notes':
return 'fas fa-sticky-note'; return 'fas fa-sticky-note';
case 'tip':
return 'fa-solid fa-lightbulb';
case 'highlight':
return 'fa-solid fa-highlighter';
} }
} }
} }

View File

@@ -182,11 +182,7 @@ class AccessoriesController extends Controller
$accessory = $request->handleImages($accessory); $accessory = $request->handleImages($accessory);
if($request->get('redirect_option') === 'back'){ session()->put(['redirect_option' => $request->get('redirect_option')]);
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->get('redirect_option')]);
}
if ($accessory->save()) { if ($accessory->save()) {
return Helper::getRedirectOption($request, $accessory->id, 'Accessories') return Helper::getRedirectOption($request, $accessory->id, 'Accessories')

View File

@@ -13,9 +13,9 @@ use App\Models\Company;
use App\Models\Contracts\Acceptable; use App\Models\Contracts\Acceptable;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\Notifications\AcceptanceItemAcceptedNotification; use App\Notifications\AcceptanceAssetAcceptedNotification;
use App\Notifications\AcceptanceItemAcceptedToUserNotification; use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
use App\Notifications\AcceptanceItemDeclinedNotification; use App\Notifications\AcceptanceAssetDeclinedNotification;
use Exception; use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
@@ -77,6 +77,7 @@ class AcceptanceController extends Controller
$acceptance = CheckoutAcceptance::find($id); $acceptance = CheckoutAcceptance::find($id);
$assigned_user = User::find($acceptance->assigned_to_id); $assigned_user = User::find($acceptance->assigned_to_id);
$settings = Setting::getSettings(); $settings = Setting::getSettings();
$path_logo = '';
$sig_filename=''; $sig_filename='';
@@ -116,6 +117,8 @@ class AcceptanceController extends Controller
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id); $item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
// If signatures are required, make sure we have one // If signatures are required, make sure we have one
if (Setting::getSettings()->require_accept_signature == '1') { if (Setting::getSettings()->require_accept_signature == '1') {
@@ -135,17 +138,10 @@ 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))) {
$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 // Get the data array ready for the notifications and PDF generation
$data = [ $data = [
'item_tag' => $item->asset_tag, '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_model' => $item->model?->name,
'item_serial' => $item->serial, 'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name, 'item_status' => $item->assetstatus?->name,
@@ -155,16 +151,16 @@ class AcceptanceController extends Controller
'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false), 'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false), 'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
'assigned_to' => $assigned_user->display_name, 'assigned_to' => $assigned_user->display_name,
'email' => $assigned_user->email,
'employee_num' => $assigned_user->employee_num,
'site_name' => $settings->site_name, 'site_name' => $settings->site_name,
'company_name' => $item->company?->name?? $settings->site_name, 'company_name' => $item->company?->name?? $settings->site_name,
'signature' => (($sig_filename && array_key_exists('1', $encoded_image))) ? $encoded_image[1] : null, 'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
'logo' => ($encoded_logo) ?? null, 'logo' => ($settings->acceptance_pdf_logo) ? public_path() . '/uploads/' . $settings->acceptance_pdf_logo : null,
'date_settings' => $settings->date_display_format, 'date_settings' => $settings->date_display_format,
'admin' => auth()->user()->present()?->fullName,
'qty' => $acceptance->qty ?? 1, 'qty' => $acceptance->qty ?? 1,
]; ];
if ($request->input('asset_acceptance') == 'accepted') { if ($request->input('asset_acceptance') == 'accepted') {
@@ -183,13 +179,13 @@ class AcceptanceController extends Controller
// Add the attachment for the signing user into the $data array // Add the attachment for the signing user into the $data array
$data['file'] = $pdf_filename; $data['file'] = $pdf_filename;
try { try {
$assigned_user->notify((new AcceptanceItemAcceptedToUserNotification($data))->locale($assigned_user->locale)); $assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale));
} catch (\Exception $e) { } catch (\Exception $e) {
Log::warning($e); Log::warning($e);
} }
} }
try { try {
$acceptance->notify((new AcceptanceItemAcceptedNotification($data))->locale(Setting::getSettings()->locale)); $acceptance->notify((new AcceptanceAssetAcceptedNotification($data))->locale(Setting::getSettings()->locale));
} catch (\Exception $e) { } catch (\Exception $e) {
Log::warning($e); Log::warning($e);
} }
@@ -204,7 +200,7 @@ class AcceptanceController extends Controller
$acceptance->decline($sig_filename, $request->input('note')); $acceptance->decline($sig_filename, $request->input('note'));
} }
$acceptance->notify(new AcceptanceItemDeclinedNotification($data)); $acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
Log::debug('New event acceptance.'); Log::debug('New event acceptance.');
event(new CheckoutDeclined($acceptance)); event(new CheckoutDeclined($acceptance));
$return_msg = trans('admin/users/message.declined'); $return_msg = trans('admin/users/message.declined');

View File

@@ -54,15 +54,6 @@ class AccessoriesController extends Controller
'notes', 'notes',
'checkouts_count', 'checkouts_count',
'qty', 'qty',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'location',
'category',
'supplier',
'manufacturer',
]; ];
@@ -70,23 +61,10 @@ class AccessoriesController extends Controller
->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier', 'adminuser') ->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier', 'adminuser')
->withCount('checkouts as checkouts_count'); ->withCount('checkouts as checkouts_count');
$filter = []; if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
} }
if ((! is_null($filter)) && (count($filter)) > 0) {
$accessories->ByFilter($filter);
} elseif ($request->filled('search')) {
$accessories->TextSearch($request->input('search'));
}
if ($request->filled('company_id')) { if ($request->filled('company_id')) {
$accessories->where('accessories.company_id', '=', $request->input('company_id')); $accessories->where('accessories.company_id', '=', $request->input('company_id'));
} }

View File

@@ -46,20 +46,11 @@ class AssetModelsController extends Controller
'manufacturer', 'manufacturer',
'requestable', 'requestable',
'assets_count', 'assets_count',
'assets_assigned_count',
'assets_archived_count',
'remaining',
'category', 'category',
'fieldset', 'fieldset',
'deleted_at', 'deleted_at',
'updated_at', 'updated_at',
'require_serial', 'require_serial',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'manufacturer',
'category',
]; ];
$assetmodels = AssetModel::select([ $assetmodels = AssetModel::select([
@@ -82,28 +73,7 @@ class AssetModelsController extends Controller
'models.require_serial' 'models.require_serial'
]) ])
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser') ->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
->withCount('assets as assets_count') ->withCount('assets as assets_count');
->withCount('availableAssets as remaining')
->withCount('assignedAssets as assets_assigned_count')
->withCount('archivedAssets as assets_archived_count');
$filter = [];
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
}
if ((! is_null($filter)) && (count($filter)) > 0) {
$assetmodels->ByFilter($filter);
} elseif ($request->filled('search')) {
$assetmodels->TextSearch($request->input('search'));
}
if ($request->input('status')=='deleted') { if ($request->input('status')=='deleted') {
$assetmodels->onlyTrashed(); $assetmodels->onlyTrashed();

View File

@@ -3,38 +3,36 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Events\CheckoutableCheckedIn; 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\StoreAssetRequest;
use App\Http\Requests\UpdateAssetRequest; use App\Http\Requests\UpdateAssetRequest;
use App\Http\Traits\MigratesLegacyAssetLocations; use App\Http\Traits\MigratesLegacyAssetLocations;
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\AssetsTransformer;
use App\Http\Transformers\ComponentsTransformer;
use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\SelectlistTransformer;
use App\Models\AccessoryCheckout;
use App\Models\Asset; use App\Models\Asset;
use App\Models\AssetModel; use App\Models\AssetModel;
use App\Models\CheckoutAcceptance;
use App\Models\Company; use App\Models\Company;
use App\Models\CustomField; use App\Models\CustomField;
use App\Models\License; use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location; use App\Models\Location;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\View\Label;
use Carbon\Carbon; 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\DB;
use Illuminate\Support\Facades\Gate; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\View\Label;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
@@ -57,7 +55,7 @@ class AssetsController extends Controller
* @param int $assetId * @param int $assetId
* @since [v4.0] * @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
{ {
@@ -117,22 +115,6 @@ class AssetsController extends Controller
'asset_eol_date', 'asset_eol_date',
'requestable', 'requestable',
'jobtitle', 'jobtitle',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'model',
'location',
'rtd_location',
'category',
'status_label',
'manufacturer',
'supplier',
'jobtitle',
'assigned_to',
'created_by',
]; ];
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load $all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
@@ -149,7 +131,6 @@ class AssetsController extends Controller
$filter = array_filter($filter, function ($key) use ($allowed_columns) { $filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns); return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY); }, ARRAY_FILTER_USE_KEY);
} }
$assets = Asset::select('assets.*') $assets = Asset::select('assets.*')
@@ -184,7 +165,7 @@ class AssetsController extends Controller
// Search custom fields by column name // Search custom fields by column name
foreach ($all_custom_fields as $field) { foreach ($all_custom_fields as $field) {
if ($request->filled($field->db_column_name()) && $field->db_column_name()) { if ($request->filled($field->db_column_name()) && $field->db_column_name()) {
$assets->where('assets.'.$field->db_column_name(), '=', $request->input($field->db_column_name())); $assets->where($field->db_column_name(), '=', $request->input($field->db_column_name()));
} }
} }
@@ -1341,18 +1322,6 @@ class AssetsController extends Controller
return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total); return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total);
} }
public function assignedComponents(Request $request, Asset $asset): JsonResponse|array
{
$this->authorize('view', Asset::class);
$this->authorize('view', $asset);
$asset->loadCount('components');
$total = $asset->components_count;
$components = $asset->load(['components' => fn($query) => $query->applyOffsetAndLimit($total)])->components;
return (new ComponentsTransformer)->transformComponents($components, $total);
}
/** /**
* Generate asset labels by tag * Generate asset labels by tag

View File

@@ -2,8 +2,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Actions\Categories\DestroyCategoryAction;
use App\Exceptions\ItemStillHasChildren;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Transformers\CategoriesTransformer; use App\Http\Transformers\CategoriesTransformer;
@@ -43,7 +41,6 @@ class CategoriesController extends Controller
'created_at', 'created_at',
'updated_at', 'updated_at',
'image', 'image',
'tag_color',
'notes', 'notes',
]; ];
@@ -58,30 +55,12 @@ class CategoriesController extends Controller
'require_acceptance', 'require_acceptance',
'checkin_email', 'checkin_email',
'image', 'image',
'tag_color',
'notes', 'notes',
]) ])
->with('adminuser') ->with('adminuser')
->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count'); ->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count');
$filter = [];
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
}
if ((! is_null($filter)) && (count($filter)) > 0) {
$categories->ByFilter($filter);
} elseif ($request->filled('search')) {
$categories->TextSearch($request->input('search'));
}
/* /*
* This checks to see if we should override the Admin Setting to show archived assets in list. * This checks to see if we should override the Admin Setting to show archived assets in list.
* We don't currently use it within the Snipe-IT GUI, but will be useful for API integrations where they * We don't currently use it within the Snipe-IT GUI, but will be useful for API integrations where they
@@ -95,6 +74,10 @@ class CategoriesController extends Controller
$categories = $categories->withCount('showableAssets as assets_count'); $categories = $categories->withCount('showableAssets as assets_count');
} }
if ($request->filled('search')) {
$categories = $categories->TextSearch($request->input('search'));
}
if ($request->filled('name')) { if ($request->filled('name')) {
$categories->where('name', '=', $request->input('name')); $categories->where('name', '=', $request->input('name'));
} }
@@ -228,21 +211,17 @@ class CategoriesController extends Controller
* @param int $id * @param int $id
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy(Category $category): JsonResponse public function destroy($id) : JsonResponse
{ {
$this->authorize('delete', Category::class); $this->authorize('delete', Category::class);
try { $category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count')->findOrFail($id);
DestroyCategoryAction::run(category: $category);
} catch (ItemStillHasChildren $e) { if (! $category->isDeletable()) {
return response()->json( return response()->json(
Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.general_assoc_warning', ['asset_type' => $category->category_type])) Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>$category->category_type]))
);
} catch (\Exception $e) {
report($e);
return response()->json(
Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong'))
); );
} }
$category->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success'))); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success')));
} }

View File

@@ -38,7 +38,6 @@ class CompaniesController extends Controller
'accessories_count', 'accessories_count',
'consumables_count', 'consumables_count',
'components_count', 'components_count',
'tag_color',
'notes', 'notes',
]; ];
@@ -65,11 +64,6 @@ class CompaniesController extends Controller
$companies->where('created_by', '=', $request->input('created_by')); $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 // 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'); $offset = ($request->input('offset') > $companies->count()) ? $companies->count() : app('api_offset_value');
@@ -197,7 +191,6 @@ class CompaniesController extends Controller
'companies.name', 'companies.name',
'companies.email', 'companies.email',
'companies.image', 'companies.image',
'companies.tag_color',
]); ]);

View File

@@ -45,40 +45,16 @@ class ComponentsController extends Controller
'qty', 'qty',
'image', 'image',
'notes', 'notes',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'location',
'category',
'manufacturer',
'supplier',
]; ];
$components = Component::select('components.*') $components = Component::select('components.*')
->with('company', 'location', 'category', 'supplier', 'adminuser', 'manufacturer') ->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets')
->withSum('uncontrainedAssets as sum_unconstrained_assets', 'components_assets.assigned_qty'); ->withSum('uncontrainedAssets', 'components_assets.assigned_qty');
$filter = [];
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
if ($request->filled('search')) {
$components = $components->TextSearch($request->input('search'));
} }
if ((! is_null($filter)) && (count($filter)) > 0) {
$components->ByFilter($filter);
} elseif ($request->filled('search')) {
$components->TextSearch($request->input('search'));
}
if ($request->filled('name')) { if ($request->filled('name')) {
$components->where('name', '=', $request->input('name')); $components->where('name', '=', $request->input('name'));
} }
@@ -112,8 +88,7 @@ class ComponentsController extends Controller
} }
// Make sure the offset and limit are actually integers and do not exceed system limits // 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'); $limit = app('api_limit_value');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc'; $order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -144,7 +119,7 @@ class ComponentsController extends Controller
break; break;
} }
$total = $components_count; $total = $components->count();
$components = $components->skip($offset)->take($limit)->get(); $components = $components->skip($offset)->take($limit)->get();
return (new ComponentsTransformer)->transformComponents($components, $total); return (new ComponentsTransformer)->transformComponents($components, $total);

View File

@@ -31,53 +31,10 @@ class ConsumablesController extends Controller
$consumables = Consumable::with('company', 'location', 'category', 'supplier', 'manufacturer') $consumables = Consumable::with('company', 'location', 'category', 'supplier', 'manufacturer')
->withCount('users as consumables_users_count'); ->withCount('users as consumables_users_count');
// This array is what determines which fields should be allowed to be sorted on ON the table itself. if ($request->filled('search')) {
// These must match a column on the consumables table directly. $consumables = $consumables->TextSearch(e($request->input('search')));
$allowed_columns = [
'id',
'name',
'order_number',
'min_amt',
'purchase_date',
'purchase_cost',
'company',
'category',
'model_number',
'item_no',
'manufacturer',
'location',
'qty',
'image',
// These are *relationships* so we wouldn't normally include them in this array,
// since they would normally create a `column not found` error,
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'location',
'category',
'supplier',
'manufacturer',
];
$filter = [];
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
return in_array($key, $allowed_columns);
}, ARRAY_FILTER_USE_KEY);
} }
if ((! is_null($filter)) && (count($filter)) > 0) {
$consumables->ByFilter($filter);
} elseif ($request->filled('search')) {
$consumables->TextSearch($request->input('search'));
}
if ($request->filled('name')) { if ($request->filled('name')) {
$consumables->where('name', '=', $request->input('name')); $consumables->where('name', '=', $request->input('name'));
} }
@@ -139,6 +96,25 @@ class ConsumablesController extends Controller
$consumables = $consumables->OrderByCreatedBy($order); $consumables = $consumables->OrderByCreatedBy($order);
break; break;
default: default:
// This array is what determines which fields should be allowed to be sorted on ON the table itself.
// These must match a column on the consumables table directly.
$allowed_columns = [
'id',
'name',
'order_number',
'min_amt',
'purchase_date',
'purchase_cost',
'company',
'category',
'model_number',
'item_no',
'manufacturer',
'location',
'qty',
'image'
];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at'; $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$consumables = $consumables->orderBy($sort, $order); $consumables = $consumables->orderBy($sort, $order);
break; break;

View File

@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\StoreDepartmentRequest;
use App\Http\Transformers\DepartmentsTransformer; use App\Http\Transformers\DepartmentsTransformer;
use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\SelectlistTransformer;
use App\Models\Department; use App\Models\Department;
@@ -24,23 +23,21 @@ class DepartmentsController extends Controller
public function index(Request $request) : JsonResponse | array public function index(Request $request) : JsonResponse | array
{ {
$this->authorize('view', Department::class); $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 = Department::select(
[ 'departments.id',
'departments.id', 'departments.name',
'departments.name', 'departments.phone',
'departments.phone', 'departments.fax',
'departments.fax', 'departments.location_id',
'departments.location_id', 'departments.company_id',
'departments.company_id', 'departments.manager_id',
'departments.manager_id', 'departments.created_at',
'departments.created_at', 'departments.updated_at',
'departments.updated_at', 'departments.image',
'departments.image', 'departments.notes',
'departments.tag_color', )->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
'departments.notes'
])->with('location')->with('manager')->with('company')->withCount('users as users_count');
if ($request->filled('search')) { if ($request->filled('search')) {
$departments = $departments->TextSearch($request->input('search')); $departments = $departments->TextSearch($request->input('search'));
@@ -62,10 +59,6 @@ class DepartmentsController extends Controller
$departments->where('location_id', '=', $request->input('location_id')); $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 // 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'); $offset = ($request->input('offset') > $departments->count()) ? $departments->count() : app('api_offset_value');
$limit = app('api_limit_value'); $limit = app('api_limit_value');
@@ -101,17 +94,18 @@ class DepartmentsController extends Controller
* @since [v4.0] * @since [v4.0]
* @param \App\Http\Requests\ImageUploadRequest $request * @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 = new Department;
$department->fill($request->validated()); $department->fill($request->all());
$department = $request->handleImages($department); $department = $request->handleImages($department);
$department->created_by = auth()->id(); $department->created_by = auth()->id();
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null); $department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
if ($department->save()) { 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())); return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
@@ -127,7 +121,7 @@ class DepartmentsController extends Controller
public function show($id) : array public function show($id) : array
{ {
$this->authorize('view', Department::class); $this->authorize('view', Department::class);
$department = Department::withCount('users as users_count')->findOrFail($id); $department = Department::findOrFail($id);
return (new DepartmentsTransformer)->transformDepartment($department); return (new DepartmentsTransformer)->transformDepartment($department);
} }
@@ -147,7 +141,7 @@ class DepartmentsController extends Controller
$department = $request->handleImages($department); $department = $request->handleImages($department);
if ($department->save()) { 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())); return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
@@ -191,7 +185,6 @@ class DepartmentsController extends Controller
'id', 'id',
'name', 'name',
'image', 'image',
'tag_color',
]); ]);
if ($request->filled('search')) { if ($request->filled('search')) {

View File

@@ -24,7 +24,7 @@ class GroupsController extends Controller
$this->authorize('view', Group::class); $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')) { if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search')); $groups = $groups->TextSearch($request->input('search'));
@@ -50,7 +50,6 @@ class GroupsController extends Controller
'id', 'id',
'name', 'name',
'created_at', 'created_at',
'updated_at',
'users_count', 'users_count',
]; ];

View File

@@ -26,11 +26,11 @@ class LicenseSeatsController extends Controller
if ($license = License::find($licenseId)) { if ($license = License::find($licenseId)) {
$this->authorize('view', $license); $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); ->where('license_seats.license_id', $licenseId);
if ($request->input('status') == 'available') { 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') { if ($request->input('status') == 'assigned') {
@@ -40,10 +40,8 @@ class LicenseSeatsController extends Controller
$order = $request->input('order') === 'asc' ? 'asc' : 'desc'; $order = $request->input('order') === 'asc' ? 'asc' : 'desc';
if ($request->input('sort') == 'assigned_user.department') { if ($request->input('sort') == 'department') {
$seats->OrderDepartments($order); $seats->OrderDepartments($order);
} elseif ($request->input('sort') == 'assigned_user.company') {
$seats->OrderCompany($order);
} else { } else {
$seats->orderBy('updated_at', $order); $seats->orderBy('updated_at', $order);
} }
@@ -79,14 +77,17 @@ class LicenseSeatsController extends Controller
{ {
$this->authorize('view', License::class); $this->authorize('view', License::class);
// sanity checks:
if ($licenseSeat = LicenseSeat::where('license_id', $licenseId)->find($seatId)) { // 1. does the license seat exist?
return (new LicenseSeatsTransformer)->transformLicenseSeat($licenseSeat); 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 // check if this update is a checkin operation
// 1. are relevant fields touched at all? // 1. are relevant fields touched at all?
$assignmentTouched = $licenseSeat->isDirty('assigned_to') || $licenseSeat->isDirty('asset_id'); $touched = $licenseSeat->isDirty('assigned_to') || $licenseSeat->isDirty('asset_id');
$anythingTouched = $licenseSeat->isDirty(); // 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) { if (! $touched) {
return response()->json( // nothing to update
Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')) 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'))); 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, // 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... // we simply let assets take precedence over users...
if ($licenseSeat->isDirty('assigned_to')) { if ($licenseSeat->isDirty('assigned_to')) {
@@ -144,23 +140,25 @@ class LicenseSeatsController extends Controller
$target = $is_checkin ? $oldAsset : Asset::find($licenseSeat->asset_id); $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')); return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
} }
if ($licenseSeat->save()) { if ($licenseSeat->save()) {
if($assignmentTouched) {
if ($is_checkin) { if ($is_checkin) {
if (!$licenseSeat->license->reassignable) { if(!$licenseSeat->license->reassignable){
$licenseSeat->unreassignable_seat = true; $licenseSeat->unreassignable_seat = true;
$licenseSeat->save(); $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);
} }
$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'))); return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
} }

View File

@@ -7,7 +7,6 @@ use App\Http\Controllers\Controller;
use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\SelectlistTransformer;
use App\Models\License; use App\Models\License;
use App\Models\Setting;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -26,12 +25,9 @@ class LicensesController extends Controller
$this->authorize('view', License::class); $this->authorize('view', License::class);
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count'); $licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
$settings = Setting::getSettings();
if ($request->input('status')=='inactive') { if ($request->input('status')=='inactive') {
$licenses->ExpiredLicenses(); $licenses->ExpiredLicenses();
} elseif ($request->input('status')=='expiring') {
$licenses->ExpiringLicenses($settings->alert_interval);
} else { } else {
$licenses->ActiveLicenses(); $licenses->ActiveLicenses();
} }

View File

@@ -59,7 +59,6 @@ class LocationsController extends Controller
'state', 'state',
'updated_at', 'updated_at',
'zip', 'zip',
'tag_color',
'notes', 'notes',
]; ];
@@ -82,8 +81,6 @@ class LocationsController extends Controller
'locations.ldap_ou', 'locations.ldap_ou',
'locations.currency', 'locations.currency',
'locations.company_id', 'locations.company_id',
'locations.tag_color',
'locations.tag_color',
'locations.notes', 'locations.notes',
'locations.created_by', 'locations.created_by',
'locations.deleted_at', 'locations.deleted_at',
@@ -148,10 +145,6 @@ class LocationsController extends Controller
$locations->onlyTrashed(); $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 // 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'); $offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
$limit = app('api_limit_value'); $limit = app('api_limit_value');
@@ -242,7 +235,6 @@ class LocationsController extends Controller
'locations.currency', 'locations.currency',
'locations.company_id', 'locations.company_id',
'locations.notes', 'locations.notes',
'locations.tag_color',
]) ])
->withCount('assignedAssets as assigned_assets_count') ->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count') ->withCount('assets as assets_count')
@@ -410,7 +402,6 @@ class LocationsController extends Controller
'locations.name', 'locations.name',
'locations.parent_id', 'locations.parent_id',
'locations.image', 'locations.image',
'locations.tag_color',
]); ]);
// Only scope locations if the setting is enabled // Only scope locations if the setting is enabled

View File

@@ -52,10 +52,6 @@ class MaintenancesController extends Controller
$maintenances->where('maintenances.created_by', '=', $request->input('created_by')); $maintenances->where('maintenances.created_by', '=', $request->input('created_by'));
} }
if ($request->filled('url')) {
$maintenances->where('maintenances.url', '=', $request->input('url'));
}
if ($request->filled('asset_maintenance_type')) { if ($request->filled('asset_maintenance_type')) {
$maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type')); $maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type'));
} }

View File

@@ -2,13 +2,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Actions\Manufacturers\DeleteManufacturerAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasChildren;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Transformers\ManufacturersTransformer; use App\Http\Transformers\ManufacturersTransformer;
@@ -47,7 +40,6 @@ class ManufacturersController extends Controller
'consumables_count', 'consumables_count',
'components_count', 'components_count',
'licenses_count', 'licenses_count',
'tag_color',
'notes', 'notes',
]; ];
@@ -64,7 +56,6 @@ class ManufacturersController extends Controller
'updated_at', 'updated_at',
'image', 'image',
'deleted_at', 'deleted_at',
'tag_color',
'notes', 'notes',
]) ])
->with('adminuser') ->with('adminuser')
@@ -106,10 +97,6 @@ class ManufacturersController extends Controller
$manufacturers->where('support_email', '=', $request->input('support_email')); $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 // 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'); $offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : app('api_offset_value');
$limit = app('api_limit_value'); $limit = app('api_limit_value');
@@ -197,19 +184,19 @@ class ManufacturersController extends Controller
* @since [v4.0] * @since [v4.0]
* @param int $id * @param int $id
*/ */
public function destroy(Manufacturer $manufacturer): JsonResponse public function destroy($id) : JsonResponse
{ {
$this->authorize('delete', Manufacturer::class);
$manufacturer = Manufacturer::findOrFail($id);
$this->authorize('delete', $manufacturer); $this->authorize('delete', $manufacturer);
try {
DeleteManufacturerAction::run($manufacturer); if ($manufacturer->isDeletable()) {
} catch (ItemStillHasChildren $e) { $manufacturer->delete();
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.general_assoc_warning', ['item' => trans('general.manufacturer')]))); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success')));
} catch (\Exception $e) {
report($e);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
} }
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success'))); return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.assoc_users')));
} }
/** /**
@@ -264,7 +251,6 @@ class ManufacturersController extends Controller
'id', 'id',
'name', 'name',
'image', 'image',
'tag_color',
]); ]);
if ($request->filled('search')) { if ($request->filled('search')) {

View File

@@ -2,13 +2,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Actions\Suppliers\DestroySupplierAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasMaintenances;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasLicenses;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\SelectlistTransformer;
@@ -50,13 +43,12 @@ class SuppliersController extends Controller
'accessories_count', 'accessories_count',
'components_count', 'components_count',
'consumables_count', 'consumables_count',
'tag_color',
'url', 'url',
'notes', 'notes',
]; ];
$suppliers = Supplier::select( $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('assets as assets_count')
->withCount('licenses as licenses_count') ->withCount('licenses as licenses_count')
->withCount('accessories as accessories_count') ->withCount('accessories as accessories_count')
@@ -199,40 +191,27 @@ class SuppliersController extends Controller
* @since [v4.0] * @since [v4.0]
* @param int $id * @param int $id
*/ */
public function destroy(Supplier $supplier): JsonResponse public function destroy($id) : JsonResponse
{ {
$this->authorize('delete', Supplier::class);
$supplier = Supplier::with('maintenances', 'assets', 'licenses')->withCount('maintenances as maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
$this->authorize('delete', $supplier); $this->authorize('delete', $supplier);
try {
DestroySupplierAction::run(supplier: $supplier);
} catch (ItemStillHasAssets $e) { if ($supplier->assets_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_assets', [ return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count])));
'asset_count' => (int) $supplier->assets_count, 'item' => trans('general.supplier')
])));
} catch (ItemStillHasMaintenances $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_maintenances', [
'asset_maintenances_count' => $supplier->asset_maintenances_count, 'item' => trans('general.supplier')
])));
} catch (ItemStillHasLicenses $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_licenses', [
'licenses_count' => (int) $supplier->licenses_count, 'item' => trans('general.supplier')
])));
} catch (ItemStillHasAccessories $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_accessories', [
'accessories_count' => (int) $supplier->accessories_count, 'item' => trans('general.supplier')
])));
} catch (ItemStillHasConsumables $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_consumables', [
'consumables_count' => (int) $supplier->consumables_count, 'item' => trans('general.supplier')
])));
} catch (ItemStillHasComponents $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_components', [
'components_count' => (int) $supplier->components_count, 'item' => trans('general.supplier')
])));
} catch (\Exception $e) {
report($e);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
} }
if ($supplier->maintenances_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['maintenances_count' => $supplier->maintenances_count])));
}
if ($supplier->licenses_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_licenses', ['licenses_count' => (int) $supplier->licenses_count])));
}
$supplier->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success'))); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success')));
} }
@@ -252,7 +231,6 @@ class SuppliersController extends Controller
'id', 'id',
'name', 'name',
'image', 'image',
'tag_color',
]); ]);
if ($request->filled('search')) { if ($request->filled('search')) {

View File

@@ -193,12 +193,8 @@ class UploadedFilesController extends Controller
// Check for the file // Check for the file
$log = Actionlog::query() $log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
->where('id', $file_id) ->where('item_id', $object->id)->first();
->where('action_type', 'uploaded')
->where('item_type', self::$map_object_type[$object_type])
->where('item_id', $object->id)
->first();
if ($log) { if ($log) {
// Check the file actually exists, and delete it // Check the file actually exists, and delete it
@@ -217,4 +213,4 @@ class UploadedFilesController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans_choice('general.file_upload_status.delete.error', 1)), 500); return response()->json(Helper::formatStandardApiResponse('error', null, trans_choice('general.file_upload_status.delete.error', 1)), 500);
} }
} }

View File

@@ -31,7 +31,6 @@ use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Http\Requests\DeleteUserRequest; use App\Http\Requests\DeleteUserRequest;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use App\Http\Requests\FilterRequest;
class UsersController extends Controller class UsersController extends Controller
{ {
@@ -43,7 +42,7 @@ class UsersController extends Controller
* *
* @return array * @return array
*/ */
public function index(FilterRequest $request) : array public function index(Request $request) : array
{ {
$this->authorize('view', User::class); $this->authorize('view', User::class);
@@ -104,80 +103,9 @@ class UsersController extends Controller
'managedLocations as manages_locations_count' 'managedLocations as manages_locations_count'
]); ]);
$allowed_columns =
[
'last_name',
'first_name',
'display_name',
'email',
'jobtitle',
'username',
'employee_num',
'groups',
'activated',
'created_at',
'updated_at',
'two_factor_enrolled',
'two_factor_optin',
'last_login',
'assets_count',
'licenses_count',
'consumables_count',
'accessories_count',
'manages_users_count',
'manages_locations_count',
'phone',
'mobile',
'address',
'city',
'state',
'country',
'zip',
'id',
'ldap_import',
'two_factor_optin',
'two_factor_enrolled',
'remote',
'vip',
'start_date',
'end_date',
'autoassign_licenses',
'website',
'locale',
'notes',
'employee_num',
// These are *relationships* so we wouldn't normally include them in this array, if ($request->filled('search') != '') {
// since they would normally create a `column not found` error, $users = $users->TextSearch($request->input('search'));
// BUT we account for them in the ordering switch down at the end of this method
// DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW!
'company',
'location',
'department',
'manager',
'created_by',
];
$filter = [];
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);
}
if ((! is_null($filter)) && (count($filter)) > 0) {
$users->ByFilter($filter);
} elseif ($request->filled('search')) {
$users->TextSearch($request->input('search'));
} }
if ($request->filled('activated')) { if ($request->filled('activated')) {
@@ -358,6 +286,49 @@ class UsersController extends Controller
$users->orderBy('first_name', $order); $users->orderBy('first_name', $order);
break; break;
default: default:
$allowed_columns =
[
'last_name',
'first_name',
'display_name',
'email',
'jobtitle',
'username',
'employee_num',
'groups',
'activated',
'created_at',
'updated_at',
'two_factor_enrolled',
'two_factor_optin',
'last_login',
'assets_count',
'licenses_count',
'consumables_count',
'accessories_count',
'manages_users_count',
'manages_locations_count',
'phone',
'mobile',
'address',
'city',
'state',
'country',
'zip',
'id',
'ldap_import',
'two_factor_optin',
'two_factor_enrolled',
'remote',
'vip',
'start_date',
'end_date',
'autoassign_licenses',
'website',
'locale',
'notes',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name'; $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name';
$users = $users->orderBy($sort, $order); $users = $users->orderBy($sort, $order);
break; break;

View File

@@ -363,7 +363,7 @@ class AssetsController extends Controller
$asset->purchase_cost = $request->input('purchase_cost', null); $asset->purchase_cost = $request->input('purchase_cost', null);
$asset->purchase_date = $request->input('purchase_date', null); $asset->purchase_date = $request->input('purchase_date', null);
$asset->next_audit_date = $request->input('next_audit_date', null); $asset->next_audit_date = $request->input('next_audit_date', null);
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model?->eol > 0)) { if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
$asset->purchase_date = $request->input('purchase_date', null); $asset->purchase_date = $request->input('purchase_date', null);
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d'); $asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
$asset->eol_explicit = false; $asset->eol_explicit = false;
@@ -379,7 +379,7 @@ class AssetsController extends Controller
} else { } else {
$asset->eol_explicit = true; $asset->eol_explicit = true;
} }
} elseif (!$request->filled('asset_eol_date') && (($asset->model?->eol) == 0)) { } elseif (!$request->filled('asset_eol_date') && (($asset->model->eol) == 0)) {
$asset->asset_eol_date = null; $asset->asset_eol_date = null;
$asset->eol_explicit = false; $asset->eol_explicit = false;
} }
@@ -398,7 +398,6 @@ class AssetsController extends Controller
$asset->assigned_to = null; $asset->assigned_to = null;
$asset->assigned_type = null; $asset->assigned_type = null;
$asset->accepted = null; $asset->accepted = null;
$asset->last_checkin = now();
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues)); event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues));
} }

View File

@@ -163,7 +163,7 @@ class BulkAssetsController extends Controller
$modelNames = []; $modelNames = [];
foreach($models as $model) { foreach($models as $model) {
$modelNames[] = $model->model?->name; $modelNames[] = $model->model->name;
} }
if ($request->filled('bulk_actions')) { if ($request->filled('bulk_actions')) {
@@ -240,6 +240,10 @@ class BulkAssetsController extends Controller
$custom_fields_to_null[str_replace('null', '', $key)] = $value; $custom_fields_to_null[str_replace('null', '', $key)] = $value;
} }
if (! $request->filled('ids') || count($request->input('ids')) == 0) { if (! $request->filled('ids') || count($request->input('ids')) == 0) {
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected')); return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
@@ -270,7 +274,6 @@ class BulkAssetsController extends Controller
|| ($request->filled('company_id')) || ($request->filled('company_id'))
|| ($request->filled('status_id')) || ($request->filled('status_id'))
|| ($request->filled('model_id')) || ($request->filled('model_id'))
|| ($request->filled('notes'))
|| ($request->filled('next_audit_date')) || ($request->filled('next_audit_date'))
|| ($request->filled('asset_eol_date')) || ($request->filled('asset_eol_date'))
|| ($request->filled('null_name')) || ($request->filled('null_name'))
@@ -467,7 +470,7 @@ class BulkAssetsController extends Controller
*/ */
// Does the model have a fieldset? // Does the model have a fieldset?
if ($asset->model?->fieldset) { if ($asset->model->fieldset) {
foreach ($asset->model->fieldset->fields as $field) { foreach ($asset->model->fieldset->fields as $field) {
// null custom fields // null custom fields
@@ -618,25 +621,9 @@ class BulkAssetsController extends Controller
{ {
$this->authorize('checkout', Asset::class); $this->authorize('checkout', Asset::class);
$alreadyAssigned = collect();
if (old('selected_assets') && is_array(old('selected_assets'))) {
$assets = Asset::findMany(old('selected_assets'));
[$assignable, $alreadyAssigned] = $assets->partition(function (Asset $asset) {
return !$asset->assigned_to;
});
session()->flashInput(['selected_assets' => $assignable->pluck('id')->values()->toArray()]);
}
$do_not_change = ['' => trans('general.do_not_change')]; $do_not_change = ['' => trans('general.do_not_change')];
$status_label_list = $do_not_change + Helper::deployableStatusLabelList(); $status_label_list = $do_not_change + Helper::deployableStatusLabelList();
return view('hardware/bulk-checkout')->with('statusLabel_list', $status_label_list);
return view('hardware/bulk-checkout', [
'statusLabel_list' => $status_label_list,
'removed_assets' => $alreadyAssigned,
]);
} }
/** /**
@@ -669,21 +656,6 @@ class BulkAssetsController extends Controller
->with('error', trans('general.error_assets_already_checked_out')); ->with('error', trans('general.error_assets_already_checked_out'));
} }
// Prevent checking out assets across companies if FMCS enabled
if (Setting::getSettings()->full_multiple_companies_support && $target->company_id) {
$company_ids = $assets->pluck('company_id')->unique();
// if there is more than one unique company id or the singular company id does not match
// then the checkout is invalid
if ($company_ids->count() > 1 || $company_ids->first() != $target->company_id) {
// re-add the asset ids so the assets select is re-populated
$request->session()->flashInput(['selected_assets' => $asset_ids]);
return redirect(route('hardware.bulkcheckout.show'))
->with('error', trans('general.error_user_company_multiple'));
}
}
if (request('checkout_to_type') == 'asset') { if (request('checkout_to_type') == 'asset') {
foreach ($asset_ids as $asset_id) { foreach ($asset_ids as $asset_id) {
if ($target->id == $asset_id) { if ($target->id == $asset_id) {

View File

@@ -1,59 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Categories\DestroyCategoryAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssetModels;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Models\Category;
use Illuminate\Http\Request;
class BulkCategoriesController extends Controller
{
public function destroy(Request $request)
{
$this->authorize('delete', Category::class);
$errors = [];
$success_count = 0;
foreach ($request->ids as $id) {
$category = Category::find($id);
if (is_null($category)) {
$errors[] = trans('admin/categories/message.does_not_exist');
continue;
}
try {
DestroyCategoryAction::run(category: $category);
$success_count++;
} catch (ItemStillHasAccessories $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_assets_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);
} catch (ItemStillHasAssetModels) {
$errors[] = trans('general.bulk_delete_associations.assoc_asset_models_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);
} catch (ItemStillHasAssets) {
$errors[] = trans('general.bulk_delete_associations.assoc_assets_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);
} catch (ItemStillHasComponents) {
$errors[] = trans('general.bulk_delete_associations.assoc_components_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);
} catch (ItemStillHasConsumables) {
$errors[] = trans('general.bulk_delete_associations.assoc_consumables_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);
} catch (ItemStillHasLicenses) {
$errors[] = trans('general.bulk_delete_associations.assoc_licenses_no_count', ['item_name' => $category->name, 'item' => trans('general.category')]);;
} catch (\Exception $e) {
report($e);
$errors[] = trans('general.something_went_wrong');
}
}
if (count($errors) > 0) {
if ($success_count > 0) {
return redirect()->route('categories.index')->with('success', trans_choice('admin/categories/message.delete.partial_success', $success_count, ['count' => $success_count]))->with('multi_error_messages', $errors);
}
return redirect()->route('categories.index')->with('multi_error_messages', $errors);
} else {
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.bulk_success'));
}
}
}

View File

@@ -1,57 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Manufacturers\DeleteManufacturerAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssetModels;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasChildren;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Models\Manufacturer;
use Illuminate\Http\Request;
class BulkManufacturersController extends Controller
{
public function destroy(Request $request)
{
$this->authorize('delete', Manufacturer::class);
$errors = [];
$success_count = 0;
foreach ($request->ids as $id) {
$manufacturer = Manufacturer::find($id);
if (is_null($manufacturer)) {
$errors[] = trans('admin/manufacturers/message.does_not_exist');
continue;
}
try {
DeleteManufacturerAction::run(manufacturer: $manufacturer);
$success_count++;
} catch (ItemStillHasAssets $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_assets_no_count', ['item_name' => $manufacturer->name, 'item' => trans('general.manufacturer')]);
} catch (ItemStillHasAccessories $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_accessories_no_count', ['item_name' => $manufacturer->name, 'item' => trans('general.manufacturer')]);
} catch (ItemStillHasConsumables $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_consumables_no_count', ['item_name' => $manufacturer->name, 'item' => trans('general.manufacturer')]);
} catch (ItemStillHasComponents $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_components_no_count', ['item_name' => $manufacturer->name, 'item' => trans('general.manufacturer')]);
} catch (ItemStillHasLicenses $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_licenses_no_count', ['item_name' => $manufacturer->name, 'item' => trans('general.manufacturer')]);;
} catch (\Exception $e) {
report($e);
$errors[] = trans('general.something_went_wrong');
}
}
if (count($errors) > 0) {
if ($success_count > 0) {
return redirect()->route('manufacturers.index')->with('success', trans_choice('admin/manufacturers/message.delete.partial_success', $success_count, ['count' => $success_count]))->with('multi_error_messages', $errors);
}
return redirect()->route('manufacturers.index')->with('multi_error_messages', $errors);
} else {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.delete.bulk_success'));
}
}
}

View File

@@ -1,58 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Suppliers\DestroySupplierAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasMaintenances;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasLicenses;
use App\Models\Supplier;
use Illuminate\Http\Request;
class BulkSuppliersController extends Controller
{
public function destroy(Request $request)
{
$this->authorize('delete', Supplier::class);
$errors = [];
$success_count = 0;
foreach ($request->ids as $id) {
$supplier = Supplier::find($id);
if (is_null($supplier)) {
$errors[] = trans('admin/suppliers/message.delete.not_found');
continue;
}
try {
DestroySupplierAction::run(supplier: $supplier);
} catch (ItemStillHasAssets $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_assets', ['asset_count' => (int) $supplier->assets_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (ItemStillHasMaintenances $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (ItemStillHasLicenses $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_licenses', ['licenses_count' => (int) $supplier->licenses_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (ItemStillHasAccessories $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_accessories', ['accessories_count' => (int) $supplier->accessories_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (ItemStillHasConsumables $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_consumables', ['consumables_count' => (int) $supplier->consumables_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (ItemStillHasComponents $e) {
$errors[] = trans('general.bulk_delete_associations.assoc_components', ['components_count' => (int) $supplier->components_count, 'item' => trans('general.supplier'), 'item_name' => $supplier->name]);
} catch (\Exception $e) {
report($e);
$errors[] = trans('general.something_went_wrong');
}
}
if (count($errors) > 0) {
if ($success_count > 0) {
return redirect()->route('suppliers.index')->with('success', trans_choice('admin/suppliers/message.delete.partial_success', $success_count, ['count' => $success_count]))->with('multi_error_messages', $errors);
}
return redirect()->route('suppliers.index')->with('multi_error_messages', $errors);
} else {
return redirect()->route('suppliers.index')->with('success', trans('admin/suppliers/message.delete.bulk_success'));
}
}
}

View File

@@ -2,14 +2,6 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Actions\Categories\DestroyCategoryAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssetModels;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasChildren;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Models\Category; use App\Models\Category;
@@ -78,7 +70,6 @@ class CategoriesController extends Controller
$category->require_acceptance = $request->input('require_acceptance', '0'); $category->require_acceptance = $request->input('require_acceptance', '0');
$category->alert_on_response = $request->input('alert_on_response', '0'); $category->alert_on_response = $request->input('alert_on_response', '0');
$category->checkin_email = $request->input('checkin_email', '0'); $category->checkin_email = $request->input('checkin_email', '0');
$category->tag_color = $request->input('tag_color');
$category->notes = $request->input('notes'); $category->notes = $request->input('notes');
$category->created_by = auth()->id(); $category->created_by = auth()->id();
@@ -133,7 +124,6 @@ class CategoriesController extends Controller
$category->require_acceptance = $request->input('require_acceptance', '0'); $category->require_acceptance = $request->input('require_acceptance', '0');
$category->alert_on_response = $request->input('alert_on_response', '0'); $category->alert_on_response = $request->input('alert_on_response', '0');
$category->checkin_email = $request->input('checkin_email', '0'); $category->checkin_email = $request->input('checkin_email', '0');
$category->tag_color = $request->input('tag_color');
$category->notes = $request->input('notes'); $category->notes = $request->input('notes');
$category = $request->handleImages($category); $category = $request->handleImages($category);
@@ -153,18 +143,20 @@ class CategoriesController extends Controller
* @since [v1.0] * @since [v1.0]
* @param int $categoryId * @param int $categoryId
*/ */
public function destroy(Category $category): RedirectResponse public function destroy($categoryId) : RedirectResponse
{ {
$this->authorize('delete', Category::class); $this->authorize('delete', Category::class);
try { // Check if the category exists
DestroyCategoryAction::run($category); if (is_null($category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count')->findOrFail($categoryId))) {
} catch (ItemStillHasChildren $e) { return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
return redirect()->route('categories.index')->with('error', trans('general.bulk_delete_associations.general_assoc_warning', ['item' => trans('general.category')]));
} catch (\Exception $e) {
report($e);
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.delete.error'));
} }
if (! $category->isDeletable()) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=> $category->category_type]));
}
Storage::disk('public')->delete('categories'.'/'.$category->image);
$category->delete();
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success')); return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success'));
} }

View File

@@ -60,7 +60,6 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone'); $company->phone = $request->input('phone');
$company->fax = $request->input('fax'); $company->fax = $request->input('fax');
$company->email = $request->input('email'); $company->email = $request->input('email');
$company->tag_color = $request->input('tag_color');
$company->notes = $request->input('notes'); $company->notes = $request->input('notes');
$company->created_by = auth()->id(); $company->created_by = auth()->id();
@@ -103,7 +102,6 @@ final class CompaniesController extends Controller
$company->phone = $request->input('phone'); $company->phone = $request->input('phone');
$company->fax = $request->input('fax'); $company->fax = $request->input('fax');
$company->email = $request->input('email'); $company->email = $request->input('email');
$company->tag_color = $request->input('tag_color');
$company->notes = $request->input('notes'); $company->notes = $request->input('notes');
$company = $request->handleImages($company); $company = $request->handleImages($company);

View File

@@ -30,7 +30,6 @@ use App\Models\Consumable;
use App\Models\License; use App\Models\License;
use App\Models\Location; use App\Models\Location;
use App\Models\Maintenance; use App\Models\Maintenance;
use App\Models\Supplier;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
@@ -46,14 +45,12 @@ abstract class Controller extends BaseController
'accessories' => Accessory::class, 'accessories' => Accessory::class,
'maintenances' => Maintenance::class, 'maintenances' => Maintenance::class,
'assets' => Asset::class, 'assets' => Asset::class,
'audits' => Asset::class,
'components' => Component::class, 'components' => Component::class,
'consumables' => Consumable::class, 'consumables' => Consumable::class,
'hardware' => Asset::class, 'hardware' => Asset::class,
'licenses' => License::class, 'licenses' => License::class,
'locations' => Location::class, 'locations' => Location::class,
'models' => AssetModel::class, 'models' => AssetModel::class,
'suppliers' => Supplier::class,
'users' => User::class, 'users' => User::class,
]; ];
@@ -61,14 +58,12 @@ abstract class Controller extends BaseController
'accessories' => 'private_uploads/accessories/', 'accessories' => 'private_uploads/accessories/',
'maintenances' => 'private_uploads/maintenances/', 'maintenances' => 'private_uploads/maintenances/',
'assets' => 'private_uploads/assets/', 'assets' => 'private_uploads/assets/',
'audits' => 'private_uploads/audits/',
'components' => 'private_uploads/components/', 'components' => 'private_uploads/components/',
'consumables' => 'private_uploads/consumables/', 'consumables' => 'private_uploads/consumables/',
'hardware' => 'private_uploads/assets/', 'hardware' => 'private_uploads/assets/',
'licenses' => 'private_uploads/licenses/', 'licenses' => 'private_uploads/licenses/',
'locations' => 'private_uploads/locations/', 'locations' => 'private_uploads/locations/',
'models' => 'private_uploads/models/', 'models' => 'private_uploads/models/',
'suppliers' => 'private_uploads/suppliers/',
'users' => 'private_uploads/users/', 'users' => 'private_uploads/users/',
]; ];
@@ -76,14 +71,12 @@ abstract class Controller extends BaseController
'accessories' => 'accessory', 'accessories' => 'accessory',
'maintenances' => 'maintenance', 'maintenances' => 'maintenance',
'assets' => 'asset', 'assets' => 'asset',
'audits' => 'audits',
'components' => 'component', 'components' => 'component',
'consumables' => 'consumable', 'consumables' => 'consumable',
'hardware' => 'asset', 'hardware' => 'asset',
'licenses' => 'license', 'licenses' => 'license',
'locations' => 'location', 'locations' => 'location',
'models' => 'model', 'models' => 'model',
'suppliers' => 'supplier',
'users' => 'user', 'users' => 'user',
]; ];

View File

@@ -55,7 +55,6 @@ class DepartmentsController extends Controller
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null); $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->location_id = ($request->filled('location_id') ? $request->input('location_id') : null);
$department->company_id = ($request->filled('company_id') ? $request->input('company_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->notes = $request->input('notes');
$department = $request->handleImages($department); $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->company_id = ($request->filled('company_id') ? $request->input('company_id') : null);
$department->phone = $request->input('phone'); $department->phone = $request->input('phone');
$department->fax = $request->input('fax'); $department->fax = $request->input('fax');
$department->tag_color = $request->input('tag_color');
$department->notes = $request->input('notes'); $department->notes = $request->input('notes');
$department = $request->handleImages($department); $department = $request->handleImages($department);

View File

@@ -7,7 +7,6 @@ use App\Models\Group;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View; use \Illuminate\Contracts\View\View;
use \App\Models\User;
/** /**
* This controller handles all actions related to User Groups for * This controller handles all actions related to User Groups for
@@ -44,20 +43,9 @@ class GroupsController extends Controller
$permissions = config('permissions'); $permissions = config('permissions');
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions); $groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
$selectedPermissions = $request->old('permissions', $groupPermissions); $selectedPermissions = $request->old('permissions', $groupPermissions);
$users_query = User::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 // Show the page
return view('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions')) return view('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions'))->with('group', $group);
->with('group', $group)
->with('associated_users', [])
->with('unselected_users', $users)
->with('all_users_count', $users_count);
} }
/** /**
@@ -72,23 +60,11 @@ class GroupsController extends Controller
// create a new group instance // create a new group instance
$group = new Group(); $group = new Group();
$group->name = $request->input('name'); $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->permissions = json_encode($request->input('permission'));
$group->created_by = auth()->id(); $group->created_by = auth()->id();
$group->notes = $request->input('notes'); $group->notes = $request->input('notes');
if ($group->save()) { if ($group->save()) {
if ($request->filled('users_to_sync')) {
$associated_users = explode(',',$request->input('users_to_sync'));
$group->users()->sync($associated_users);
}
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create')); return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
} }
@@ -111,26 +87,8 @@ class GroupsController extends Controller
if ((!is_array($groupPermissions)) || (!$groupPermissions)) { if ((!is_array($groupPermissions)) || (!$groupPermissions)) {
$groupPermissions = []; $groupPermissions = [];
} }
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions); $selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
$users_query = User::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::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);
} }
/** /**
@@ -144,24 +102,11 @@ class GroupsController extends Controller
public function update(Request $request, Group $group) : RedirectResponse public function update(Request $request, Group $group) : RedirectResponse
{ {
$group->name = $request->input('name'); $group->name = $request->input('name');
$group->permissions = json_encode($request->input('permission'));
if ($request->filled('permission')) {
$group->permissions = json_encode($request->array('permission'));
} else {
$group->permissions = null;
}
$group->notes = $request->input('notes'); $group->notes = $request->input('notes');
if (! config('app.lock_passwords')) { if (! config('app.lock_passwords')) {
if ($group->save()) { if ($group->save()) {
if ($request->has('users_to_sync')) {
$associated_users = explode(',',$request->input('users_to_sync'));
$group->users()->sync($associated_users);
}
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.update')); return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.update'));
} }

View File

@@ -82,7 +82,6 @@ class LocationsController extends Controller
$location->created_by = auth()->id(); $location->created_by = auth()->id();
$location->phone = request('phone'); $location->phone = request('phone');
$location->fax = request('fax'); $location->fax = request('fax');
$location->tag_color = $request->input('tag_color');
$location->notes = $request->input('notes'); $location->notes = $request->input('notes');
$location->company_id = Company::getIdForCurrentUser($request->input('company_id')); $location->company_id = Company::getIdForCurrentUser($request->input('company_id'));
@@ -157,7 +156,6 @@ class LocationsController extends Controller
$location->fax = request('fax'); $location->fax = request('fax');
$location->ldap_ou = $request->input('ldap_ou'); $location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id'); $location->manager_id = $request->input('manager_id');
$location->tag_color = $request->input('tag_color');
$location->notes = $request->input('notes'); $location->notes = $request->input('notes');
// Only scope the location if the setting is enabled // Only scope the location if the setting is enabled

View File

@@ -78,7 +78,6 @@ class MaintenancesController extends Controller
$maintenance->is_warranty = $request->input('is_warranty'); $maintenance->is_warranty = $request->input('is_warranty');
$maintenance->cost = $request->input('cost'); $maintenance->cost = $request->input('cost');
$maintenance->notes = $request->input('notes'); $maintenance->notes = $request->input('notes');
$maintenance->url = $request->input('url');
// Save the asset maintenance data // Save the asset maintenance data
$maintenance->asset_id = $asset->id; $maintenance->asset_id = $asset->id;
@@ -153,7 +152,6 @@ class MaintenancesController extends Controller
$maintenance->name = $request->input('name'); $maintenance->name = $request->input('name');
$maintenance->start_date = $request->input('start_date'); $maintenance->start_date = $request->input('start_date');
$maintenance->completion_date = $request->input('completion_date'); $maintenance->completion_date = $request->input('completion_date');
$maintenance->url = $request->input('url');
// Todo - put this in a getter/setter? // Todo - put this in a getter/setter?

View File

@@ -2,14 +2,6 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Actions\Manufacturers\DeleteManufacturerAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasChildren;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasLicenses;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Manufacturer; use App\Models\Manufacturer;
@@ -101,7 +93,6 @@ class ManufacturersController extends Controller
$manufacturer->support_email = $request->input('support_email'); $manufacturer->support_email = $request->input('support_email');
$manufacturer->notes = $request->input('notes'); $manufacturer->notes = $request->input('notes');
$manufacturer = $request->handleImages($manufacturer); $manufacturer = $request->handleImages($manufacturer);
$manufacturer->tag_color = $request->input('tag_color');
if ($manufacturer->save()) { if ($manufacturer->save()) {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.create.success')); return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.create.success'));
@@ -143,7 +134,6 @@ class ManufacturersController extends Controller
$manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url'); $manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url');
$manufacturer->support_phone = $request->input('support_phone'); $manufacturer->support_phone = $request->input('support_phone');
$manufacturer->support_email = $request->input('support_email'); $manufacturer->support_email = $request->input('support_email');
$manufacturer->tag_color = $request->input('tag_color');
$manufacturer->notes = $request->input('notes'); $manufacturer->notes = $request->input('notes');
// Set the model's image property to null if the image is being deleted // Set the model's image property to null if the image is being deleted
@@ -167,18 +157,32 @@ class ManufacturersController extends Controller
* @param int $manufacturerId * @param int $manufacturerId
* @since [v1.0] * @since [v1.0]
*/ */
public function destroy(Manufacturer $manufacturer): RedirectResponse public function destroy($manufacturerId) : RedirectResponse
{ {
$this->authorize('delete', $manufacturer); $this->authorize('delete', Manufacturer::class);
try { if (is_null($manufacturer = Manufacturer::withTrashed()->withCount('models as models_count')->find($manufacturerId))) {
DeleteManufacturerAction::run($manufacturer); return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.not_found'));
} catch (ItemStillHasChildren $e) {
return redirect()->route('manufacturers.index')->with('error', trans('general.bulk_delete_associations.general_assoc_warning', ['item' => trans('general.manufacturer')]));
} catch (\Exception $e) {
report($e);
return redirect()->route('manufacturers.index')->with('error', trans('general.something_went_wrong'));
} }
if (! $manufacturer->isDeletable()) {
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.assoc_users'));
}
if ($manufacturer->image) {
try {
Storage::disk('public')->delete('manufacturers/'.$manufacturer->image);
} catch (\Exception $e) {
Log::info($e);
}
}
// Soft delete the manufacturer if active, permanent delete if is already deleted
if ($manufacturer->deleted_at === null) {
$manufacturer->delete();
} else {
$manufacturer->forceDelete();
}
// Redirect to the manufacturers management page
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.delete.success')); return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.delete.success'));
} }

View File

@@ -3,21 +3,12 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Mail\CheckoutAccessoryMail;
use App\Mail\CheckoutAssetMail; use App\Mail\CheckoutAssetMail;
use App\Mail\CheckoutComponentMail;
use App\Mail\CheckoutConsumableMail;
use App\Mail\CheckoutLicenseMail;
use App\Models\Accessory; use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Asset; use App\Models\Asset;
use App\Models\AssetModel; use App\Models\AssetModel;
use App\Models\Category; 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\Maintenance;
use App\Models\CheckoutAcceptance; use App\Models\CheckoutAcceptance;
use App\Models\Company; use App\Models\Company;
@@ -27,11 +18,9 @@ use App\Models\License;
use App\Models\ReportTemplate; use App\Models\ReportTemplate;
use App\Models\Setting; use App\Models\Setting;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use \Illuminate\Contracts\View\View; use \Illuminate\Contracts\View\View;
use League\Csv\Reader; use League\Csv\Reader;
@@ -447,8 +436,10 @@ class ReportsController extends Controller
// Open output stream // Open output stream
$handle = fopen('php://output', 'w'); $handle = fopen('php://output', 'w');
stream_set_timeout($handle, 2000); stream_set_timeout($handle, 2000);
fprintf($handle, chr(0xEF).chr(0xBB).chr(0xBF)); if ($request->filled('use_bom')) {
fprintf($handle, chr(0xEF).chr(0xBB).chr(0xBF));
}
$header = []; $header = [];
@@ -694,14 +685,6 @@ class ReportsController extends Controller
$assets->whereBetween('assets.purchase_date', [$request->input('purchase_start'), $request->input('purchase_end')]); $assets->whereBetween('assets.purchase_date', [$request->input('purchase_start'), $request->input('purchase_end')]);
} }
if ($request->filled('purchase_cost_start')) {
if ($request->filled('purchase_cost_end')) {
$assets->whereBetween('assets.purchase_cost', [$request->input('purchase_cost_start'), $request->input('purchase_cost_end')]);
} else {
$assets->where('assets.purchase_cost', ">", $request->input('purchase_cost_start'));
}
}
if (($request->filled('created_start')) && ($request->filled('created_end'))) { if (($request->filled('created_start')) && ($request->filled('created_end'))) {
$created_start = Carbon::parse($request->input('created_start'))->startOfDay(); $created_start = Carbon::parse($request->input('created_start'))->startOfDay();
$created_end = Carbon::parse($request->input('created_end'))->endOfDay(); $created_end = Carbon::parse($request->input('created_end'))->endOfDay();
@@ -1127,32 +1110,34 @@ class ReportsController extends Controller
$this->authorize('reports.view'); $this->authorize('reports.view');
$showDeleted = $deleted == 'deleted'; $showDeleted = $deleted == 'deleted';
$query = CheckoutAcceptance::Pending() $query = CheckoutAcceptance::pending()
->where('checkoutable_type', 'App\Models\Asset')
->with([ ->with([
'checkoutable' => function (MorphTo $query) { 'checkoutable' => function (MorphTo $query) {
$query->withTrashed()->morphWith([ $query->morphWith([
Asset::class => ['model.category', 'assignedTo', 'company'], AssetModel::class => ['model'],
Accessory::class => ['category','checkouts', 'company'], Company::class => ['company'],
LicenseSeat::class => ['user', 'license'], Asset::class => ['assignedTo'],
Component::class => ['assignedTo', 'company'], ])->with('model.category');
Consumable::class => ['company'],
]);
}, },
'assignedTo' => function($query){ 'assignedTo' => function($query){
$query->withTrashed(); $query->withTrashed();
} }
])->orderByDesc('checkout_acceptances.created_at'); ]);
if ($showDeleted) { if ($showDeleted) {
$query->withTrashed(); $query->withTrashed();
} }
$itemsForReport = $query->get() $assetsForReport = $query->get()
->filter(fn ($unaccepted) => $unaccepted->checkoutable) ->map(function ($acceptance) {
->map(fn ($unaccepted) => Checkoutable::fromAcceptance($unaccepted)); return [
'assetItem' => $acceptance->checkoutable,
'acceptance' => $acceptance,
];
});
return view('reports/unaccepted_assets', compact('itemsForReport','showDeleted' )); return view('reports/unaccepted_assets', compact('assetsForReport','showDeleted' ));
} }
/** /**
@@ -1164,77 +1149,41 @@ class ReportsController extends Controller
public function sentAssetAcceptanceReminder(Request $request) : RedirectResponse public function sentAssetAcceptanceReminder(Request $request) : RedirectResponse
{ {
$this->authorize('reports.view'); $this->authorize('reports.view');
$id = $request->input('acceptance_id');
$query = CheckoutAcceptance::query() if (!$acceptance = CheckoutAcceptance::pending()->find($request->input('acceptance_id'))) {
->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) {
Log::debug('No pending acceptances'); 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')); 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)){ if (is_null($acceptance->created_at)){
Log::debug('No acceptance created_at'); Log::debug('No acceptance created_at');
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data')); return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
} else { } else {
if($item instanceof LicenseSeat){ $logItem_res = $assetItem->checkouts()->where('created_at', '=', $acceptance->created_at)->get();
$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();
}
if ($logItem_res->isEmpty()){ if ($logItem_res->isEmpty()){
Log::debug('Acceptance date mismatch'); Log::debug('Acceptance date mismatch');
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data')); return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
} }
$logItem = $logItem_res[0]; $logItem = $logItem_res[0];
} }
$email = $assetItem->assignedTo?->email;
$locale = $assetItem->assignedTo?->locale;
if (is_null($email) || $email === '') { if (is_null($email) || $email === '') {
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_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')); 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);
}
/** /**
* sentAssetAcceptanceReminder * sentAssetAcceptanceReminder
* *
@@ -1266,43 +1215,31 @@ class ReportsController extends Controller
public function postAssetAcceptanceReport($deleted = false) : Response public function postAssetAcceptanceReport($deleted = false) : Response
{ {
$this->authorize('reports.view'); $this->authorize('reports.view');
$showDeleted = request('deleted') === 'deleted';; $showDeleted = $deleted == 'deleted';
/** /**
* Get all assets with pending checkout acceptances * 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() $assetsForReport = $acceptances
->with([ ->filter(function($acceptance) {
'checkoutable' => function (MorphTo $acceptance) { return $acceptance->checkoutable_type == 'App\Models\Asset';
$acceptance->withTrashed()->morphWith([ })
Asset::class => ['model.category', 'assignedTo', 'company'], ->map(function($acceptance) {
Accessory::class => ['category','checkouts', 'company'], return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
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));
$rows = []; $rows = [];
$header = [ $header = [
trans('general.date'),
trans('general.type'),
trans('admin/companies/table.title'),
trans('general.category'), trans('general.category'),
trans('admin/hardware/form.model'), trans('admin/hardware/form.model'),
trans('general.name'), trans('admin/hardware/form.name'),
trans('admin/hardware/table.asset_tag'), trans('admin/hardware/table.asset_tag'),
trans('admin/hardware/table.checkoutto'), trans('admin/hardware/table.checkoutto'),
]; ];
@@ -1310,19 +1247,16 @@ class ReportsController extends Controller
$header = array_map('trim', $header); $header = array_map('trim', $header);
$rows[] = implode(',', $header); $rows[] = implode(',', $header);
foreach ($itemsForReport as $item) { foreach ($assetsForReport as $item) {
if ($item != null){ if ($item['assetItem'] != null){
$row = [ ]; $row = [ ];
$row[] = str_replace(',', '', $item->acceptance->created_at); $row[] = str_replace(',', '', e($item['assetItem']->model->category->name));
$row[] = str_replace(',', '', $item->type); $row[] = str_replace(',', '', e($item['assetItem']->model->name));
$row[] = str_replace(',', '', $item->plain_text_company); $row[] = str_replace(',', '', e($item['assetItem']->name));
$row[] = str_replace(',', '', $item->plain_text_category); $row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
$row[] = str_replace(',', '', $item->plain_text_model); $row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user')));
$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'));
$rows[] = implode(',', $row); $rows[] = implode(',', $row);
} }
} }

View File

@@ -589,7 +589,6 @@ class SettingsController extends Controller
$setting->time_display_format = $request->input('time_display_format'); $setting->time_display_format = $request->input('time_display_format');
$setting->digit_separator = $request->input('digit_separator'); $setting->digit_separator = $request->input('digit_separator');
$setting->name_display_format = $request->input('name_display_format'); $setting->name_display_format = $request->input('name_display_format');
$setting->week_start = $request->input('week_start', 0);
if ($setting->save()) { if ($setting->save()) {
return redirect()->route('settings.index') return redirect()->route('settings.index')
@@ -773,7 +772,6 @@ class SettingsController extends Controller
$setting->label2_asset_logo = $request->input('label2_asset_logo'); $setting->label2_asset_logo = $request->input('label2_asset_logo');
$setting->label2_1d_type = $request->input('label2_1d_type'); $setting->label2_1d_type = $request->input('label2_1d_type');
$setting->label2_2d_type = $request->input('label2_2d_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_2d_target = $request->input('label2_2d_target');
$setting->label2_fields = $request->input('label2_fields'); $setting->label2_fields = $request->input('label2_fields');
$setting->label2_empty_row_count = $request->input('label2_empty_row_count'); $setting->label2_empty_row_count = $request->input('label2_empty_row_count');

View File

@@ -2,18 +2,10 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Actions\Suppliers\DestroySupplierAction;
use App\Exceptions\ItemStillHasAccessories;
use App\Exceptions\ItemStillHasComponents;
use App\Exceptions\ItemStillHasConsumables;
use App\Exceptions\ItemStillHasMaintenances;
use App\Exceptions\ItemStillHasAssets;
use App\Exceptions\ItemStillHasLicenses;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Models\Supplier; use App\Models\Supplier;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use \Illuminate\Contracts\View\View; use \Illuminate\Contracts\View\View;
use Illuminate\Support\MessageBag;
/** /**
* This controller handles all actions related to Suppliers for * This controller handles all actions related to Suppliers for
@@ -67,7 +59,6 @@ class SuppliersController extends Controller
$supplier->phone = request('phone'); $supplier->phone = request('phone');
$supplier->fax = request('fax'); $supplier->fax = request('fax');
$supplier->email = request('email'); $supplier->email = request('email');
$supplier->tag_color = $request->input('tag_color');
$supplier->notes = request('notes'); $supplier->notes = request('notes');
$supplier->url = $supplier->addhttp(request('url')); $supplier->url = $supplier->addhttp(request('url'));
$supplier->created_by = auth()->id(); $supplier->created_by = auth()->id();
@@ -112,7 +103,6 @@ class SuppliersController extends Controller
$supplier->fax = request('fax'); $supplier->fax = request('fax');
$supplier->email = request('email'); $supplier->email = request('email');
$supplier->url = $supplier->addhttp(request('url')); $supplier->url = $supplier->addhttp(request('url'));
$supplier->tag_color = $request->input('tag_color');
$supplier->notes = request('notes'); $supplier->notes = request('notes');
$supplier = $request->handleImages($supplier); $supplier = $request->handleImages($supplier);
@@ -128,41 +118,30 @@ class SuppliersController extends Controller
* *
* @param int $supplierId * @param int $supplierId
*/ */
public function destroy(Supplier $supplier): RedirectResponse public function destroy($supplierId) : RedirectResponse
{ {
$this->authorize('delete', Supplier::class); $this->authorize('delete', Supplier::class);
try { if (is_null($supplier = Supplier::with('maintenances', 'assets', 'licenses')->withCount('maintenances as maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->find($supplierId))) {
DestroySupplierAction::run(supplier: $supplier); return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.not_found'));
} catch (ItemStillHasAssets $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_assets', [
'asset_count' => (int) $supplier->assets_count, 'item' => trans('general.supplier')
]));
} catch (ItemStillHasMaintenances $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_maintenances', [
'asset_maintenances_count' => $supplier->asset_maintenances_count, 'item' => trans('general.supplier')
]));
} catch (ItemStillHasLicenses $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_licenses', [
'licenses_count' => (int) $supplier->licenses_count, 'item' => trans('general.supplier')
]));
} catch (ItemStillHasAccessories $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_accessories', [
'accessories_count' => (int) $supplier->accessories_count, 'item' => trans('general.supplier')
]));
} catch (ItemStillHasConsumables $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_consumables', [
'consumables_count' => (int) $supplier->consumables_count, 'item' => trans('general.supplier')
]));
} catch (ItemStillHasComponents $e) {
return redirect()->route('suppliers.index')->with('error', trans('general.bulk_delete_associations.assoc_components', [
'components_count' => (int) $supplier->components_count, 'item' => trans('general.supplier')
]));
} catch (\Exception $e) {
report($e);
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.error'));
} }
return redirect()->route('suppliers.index')->with('success', trans('admin/suppliers/message.delete.success')); if ($supplier->assets_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count]));
}
if ($supplier->maintenances_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_maintenances', ['maintenances_count' => $supplier->maintenances_count]));
}
if ($supplier->licenses_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_licenses', ['licenses_count' => (int) $supplier->licenses_count]));
}
$supplier->delete();
return redirect()->route('suppliers.index')->with('success',
trans('admin/suppliers/message.delete.success')
);
} }
/** /**
@@ -175,5 +154,6 @@ class SuppliersController extends Controller
{ {
$this->authorize('view', Supplier::class); $this->authorize('view', Supplier::class);
return view('suppliers/view', compact('supplier')); return view('suppliers/view', compact('supplier'));
} }
} }

View File

@@ -4,7 +4,6 @@ namespace App\Http\Controllers;
use App\Actions\CheckoutRequests\CancelCheckoutRequestAction; use App\Actions\CheckoutRequests\CancelCheckoutRequestAction;
use App\Actions\CheckoutRequests\CreateCheckoutRequestAction; use App\Actions\CheckoutRequests\CreateCheckoutRequestAction;
use App\Enums\ActionType;
use App\Exceptions\AssetNotRequestable; use App\Exceptions\AssetNotRequestable;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Asset; use App\Models\Asset;
@@ -156,19 +155,7 @@ class ViewAssetsController extends Controller
public function getRequestableIndex() : View public function getRequestableIndex() : View
{ {
$assets = Asset::with('model', 'defaultLoc', 'location', 'assignedTo', 'requests')->Hardware()->RequestableAssets(); $assets = Asset::with('model', 'defaultLoc', 'location', 'assignedTo', 'requests')->Hardware()->RequestableAssets();
$models = AssetModel::with([ $models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
'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();
return view('account/requestable-assets', compact('assets', 'models')); 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) { if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) {
$item->cancelRequest($requestingUser); $item->cancelRequest($requestingUser);
$data['item_quantity'] = ($item_request) ? $item_request->qty : 1; $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'))) { if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
$settings->notify(new RequestAssetCancelation($data)); $settings->notify(new RequestAssetCancelation($data));

View File

@@ -14,15 +14,6 @@ class CustomAssetReportRequest extends Request
return true; return true;
} }
public function prepareForValidation()
{
if($this->filled('purchase_cost_end') && !$this->filled('purchase_cost_start')){
$this->merge(['purchase_cost_start' => 0 ]);
}
}
/** /**
* Get the validation rules that apply to the request. * Get the validation rules that apply to the request.
* *
@@ -33,7 +24,6 @@ class CustomAssetReportRequest extends Request
return [ return [
'purchase_start' => 'date|date_format:Y-m-d|nullable', 'purchase_start' => 'date|date_format:Y-m-d|nullable',
'purchase_end' => 'date|date_format:Y-m-d|nullable', 'purchase_end' => 'date|date_format:Y-m-d|nullable',
'purchase_cost_end' => 'numeric|nullable|gte:purchase_cost_start',
'created_start' => 'date|date_format:Y-m-d|nullable', 'created_start' => 'date|date_format:Y-m-d|nullable',
'created_end' => 'date|date_format:Y-m-d|nullable', 'created_end' => 'date|date_format:Y-m-d|nullable',
'checkout_date_start' => 'date|date_format:Y-m-d|nullable', 'checkout_date_start' => 'date|date_format:Y-m-d|nullable',

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

View File

@@ -109,7 +109,7 @@ class SettingsSamlRequest extends FormRequest
]; ];
$pkey = openssl_pkey_new([ $pkey = openssl_pkey_new([
'private_key_bits' => (int) config('app.saml_key_size'), 'private_key_bits' => config('app.saml_key_size'),
'private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_type' => OPENSSL_KEYTYPE_RSA,
]); ]);

View File

@@ -26,7 +26,6 @@ class StoreAssetRequest extends ImageUploadRequest
public function prepareForValidation(): void public function prepareForValidation(): void
{ {
parent::prepareForValidation(); // call ImageUploadRequest thing
// Guard against users passing in an array for company_id instead of an integer. // Guard against users passing in an array for company_id instead of an integer.
// If the company_id is not an integer then we simply use what was // If the company_id is not an integer then we simply use what was
// provided to be caught by model level validation later. // provided to be caught by model level validation later.

View File

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

View File

@@ -49,7 +49,6 @@ class StoreLabelSettings extends FormRequest
'labels_pagewidth' => 'numeric|nullable', 'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable', 'labels_pageheight' => 'numeric|nullable',
'qr_text' => 'max:31|nullable', 'qr_text' => 'max:31|nullable',
'label2_2d_prefix' => 'nullable|max:191',
'label2_template' => [ 'label2_template' => [
'required', 'required',
Rule::in($names), Rule::in($names),

View File

@@ -32,7 +32,7 @@ class StoreNotificationSettings extends FormRequest
], ],
'alert_threshold' => 'numeric|nullable', 'alert_threshold' => 'numeric|nullable',
'alert_interval' => 'numeric|nullable|gt:0', 'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable|gte:0', 'audit_warning_days' => 'numeric|nullable',
'due_checkin_days' => 'numeric|nullable|gt:0', 'due_checkin_days' => 'numeric|nullable|gt:0',
'audit_interval' => 'numeric|nullable|gt:0', 'audit_interval' => 'numeric|nullable|gt:0',
]; ];

View File

@@ -28,31 +28,23 @@ class UpdateAssetRequest extends ImageUploadRequest
*/ */
public function rules() public function rules()
{ {
$setting = Setting::getSettings();
$rules = array_merge( $rules = array_merge(
parent::rules(), parent::rules(),
(new Asset)->getRules(), (new Asset)->getRules(),
// This overwrites the rulesets that are set at the model level (via Watson) but are not necessarily required at the request level when doing a PATCH update. // this is to overwrite rulesets that include required, and rewrite unique_undeleted
// Confusingly, this skips the unique_undeleted validator at the model level (and therefore the UniqueUndeletedTrait), so we have to re-add those
// rules here without the requiredness, since those values will already exist if you're updating an existing asset.
[ [
'model_id' => ['integer', 'exists:models,id,deleted_at,NULL', 'not_array'], 'model_id' => ['integer', 'exists:models,id,deleted_at,NULL', 'not_array'],
'status_id' => ['integer', 'exists:status_labels,id'], 'status_id' => ['integer', 'exists:status_labels,id'],
'asset_tag' => [ 'asset_tag' => [
'min:1', 'max:255', 'not_array', 'min:1', 'max:255', 'not_array',
Rule::unique('assets', 'asset_tag')->ignore($this->asset)->withoutTrashed(), Rule::unique('assets', 'asset_tag')->ignore($this->asset)->withoutTrashed()
],
'serial' => [
'string', 'max:255', 'not_array',
$setting->unique_serial=='1' ? Rule::unique('assets', 'serial')->ignore($this->asset)->withoutTrashed() : 'nullable',
], ],
], ],
); );
// if the purchase cost is passed in as a string **and** the digit_separator is ',' (as is common in the EU) // if the purchase cost is passed in as a string **and** the digit_separator is ',' (as is common in the EU)
// then we tweak the purchase_cost rule to make it a string // then we tweak the purchase_cost rule to make it a string
if ($setting->digit_separator === '1.234,56' && is_string($this->input('purchase_cost'))) { if (Setting::getSettings()->digit_separator === '1.234,56' && is_string($this->input('purchase_cost'))) {
$rules['purchase_cost'] = ['nullable', 'string']; $rules['purchase_cost'] = ['nullable', 'string'];
} }

View File

@@ -2,7 +2,6 @@
namespace App\Http\Traits; namespace App\Http\Traits;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -39,13 +38,20 @@ trait ConvertsBase64ToFiles
if (!$base64Contents) { if (!$base64Contents) {
return; return;
} }
// autogenerate filenames
if ($filename == 'auto'){
$header = explode(';', $base64Contents, 2)[0];
// Grab the image type from the header while we're at it.
$filename = $key . '.' . substr($header, strpos($header, '/')+1);
}
// Generate a temporary path to store the Base64 contents // Generate a temporary path to store the Base64 contents
$tempFilePath = tempnam(sys_get_temp_dir(), $filename); $tempFilePath = tempnam(sys_get_temp_dir(), $filename);
// Store the contents using a stream, or throw an Error (which doesn't do anything?) // Store the contents using a stream, or by decoding manually
if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) { if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) {
$source = fopen($base64Contents, 'r'); // PHP has special processing for "data:" URL's $source = fopen($base64Contents, 'r');
$destination = fopen($tempFilePath, 'w'); $destination = fopen($tempFilePath, 'w');
stream_copy_to_stream($source, $destination); stream_copy_to_stream($source, $destination);
@@ -53,8 +59,7 @@ trait ConvertsBase64ToFiles
fclose($source); fclose($source);
fclose($destination); fclose($destination);
} else { } else {
// TODO - to get a better error message here, can we maybe do something with modifying the errorBag? file_put_contents($tempFilePath, base64_decode($base64Contents, true));
throw new ValidationException("Need Base64 URL starting with 'data:'"); // This doesn't actually throw?
} }
$uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true); $uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true);

View File

@@ -26,32 +26,12 @@ class AccessoriesTransformer
'id' => $accessory->id, 'id' => $accessory->id,
'name' => e($accessory->name), 'name' => e($accessory->name),
'image' => ($accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory->image)) : null, 'image' => ($accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory->image)) : null,
'company' => ($accessory->company) ? [ 'company' => ($accessory->company) ? ['id' => $accessory->company->id, 'name'=> e($accessory->company->name)] : null,
'id' => $accessory->company->id, 'manufacturer' => ($accessory->manufacturer) ? ['id' => $accessory->manufacturer->id, 'name'=> e($accessory->manufacturer->name)] : null,
'name'=> e($accessory->company->name), 'supplier' => ($accessory->supplier) ? ['id' => $accessory->supplier->id, 'name'=> e($accessory->supplier->name)] : null,
'tag_color'=> ($accessory->company->tag_color) ? e($accessory->company->tag_color) : null,
] : null,
'manufacturer' => ($accessory->manufacturer) ? [
'id' => $accessory->manufacturer->id,
'name'=> e($accessory->manufacturer->name),
'tag_color'=> ($accessory->manufacturer->tag_color) ? e($accessory->manufacturer->tag_color) : null,
] : null,
'supplier' => ($accessory->supplier) ? [
'id' => $accessory->supplier->id,
'name'=> e($accessory->supplier->name),
'tag_color'=> ($accessory->supplier->tag_color) ? e($accessory->supplier->tag_color) : null,
] : null,
'model_number' => ($accessory->model_number) ? e($accessory->model_number) : null, 'model_number' => ($accessory->model_number) ? e($accessory->model_number) : null,
'category' => ($accessory->category) ? [ 'category' => ($accessory->category) ? ['id' => $accessory->category->id, 'name'=> e($accessory->category->name)] : null,
'id' => $accessory->category->id, 'location' => ($accessory->location) ? ['id' => $accessory->location->id, 'name'=> e($accessory->location->name)] : null,
'name'=> e($accessory->category->name),
'tag_color'=> ($accessory->category->tag_color) ? e($accessory->category->tag_color) : null,
] : null,
'location' => ($accessory->location) ? [
'id' => $accessory->location->id,
'name'=> e($accessory->location->name),
'tag_color'=> ($accessory->location->tag_color) ? e($accessory->location->tag_color) : null,
] : null,
'notes' => ($accessory->notes) ? Helper::parseEscapedMarkedownInline($accessory->notes) : null, 'notes' => ($accessory->notes) ? Helper::parseEscapedMarkedownInline($accessory->notes) : null,
'qty' => ($accessory->qty) ? (int) $accessory->qty : null, 'qty' => ($accessory->qty) ? (int) $accessory->qty : null,
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null, 'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,

View File

@@ -149,7 +149,6 @@ class ActionlogsTransformer
'filename' => $actionlog->filename, 'filename' => $actionlog->filename,
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_path()), 'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_path()),
'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false, 'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false,
'mediatype' => StorageHelper::getMediaType($actionlog->uploads_file_path()),
] : null, ] : null,
'item' => ($actionlog->item) ? [ 'item' => ($actionlog->item) ? [
@@ -161,7 +160,6 @@ class ActionlogsTransformer
'location' => ($actionlog->location) ? [ 'location' => ($actionlog->location) ? [
'id' => (int) $actionlog->location->id, 'id' => (int) $actionlog->location->id,
'name' => e($actionlog->location->name), 'name' => e($actionlog->location->name),
'tag_color'=> ($actionlog->location->tag_color) ? e($actionlog->location->tag_color) : null,
] : null, ] : null,
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),

View File

@@ -44,24 +44,19 @@ class AssetModelsTransformer
'manufacturer' => ($assetmodel->manufacturer) ? [ 'manufacturer' => ($assetmodel->manufacturer) ? [
'id' => (int) $assetmodel->manufacturer->id, 'id' => (int) $assetmodel->manufacturer->id,
'name'=> e($assetmodel->manufacturer->name), 'name'=> e($assetmodel->manufacturer->name),
'tag_color'=> ($assetmodel->manufacturer->tag_color) ? e($assetmodel->manufacturer->tag_color) : null,
] : null, ] : null,
'image' => ($assetmodel->image != '') ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null, 'image' => ($assetmodel->image != '') ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null,
'model_number' => ($assetmodel->model_number ? e($assetmodel->model_number): null), 'model_number' => ($assetmodel->model_number ? e($assetmodel->model_number): null),
'min_amt' => ($assetmodel->min_amt) ? (int) $assetmodel->min_amt : null, 'min_amt' => ($assetmodel->min_amt) ? (int) $assetmodel->min_amt : null,
'remaining' => (int) ($assetmodel->assets_count - $assetmodel->min_amt),
'depreciation' => ($assetmodel->depreciation) ? [ 'depreciation' => ($assetmodel->depreciation) ? [
'id' => (int) $assetmodel->depreciation->id, 'id' => (int) $assetmodel->depreciation->id,
'name'=> e($assetmodel->depreciation->name), 'name'=> e($assetmodel->depreciation->name),
] : null, ] : null,
'assets_count' => (int) $assetmodel->assets_count, 'assets_count' => (int) $assetmodel->assets_count,
'assets_assigned_count' => (int) $assetmodel->assets_assigned_count,
'assets_archived_count' => (int) $assetmodel->assets_archived_count,
'remaining' => (int) ($assetmodel->assets_count - (int) $assetmodel->assets_assigned_count) - (int) $assetmodel->assets_archived_count,
'category' => ($assetmodel->category) ? [ 'category' => ($assetmodel->category) ? [
'id' => (int) $assetmodel->category->id, 'id' => (int) $assetmodel->category->id,
'name'=> e($assetmodel->category->name), 'name'=> e($assetmodel->category->name),
'tag_color'=> ($assetmodel->category->tag_color) ? e($assetmodel->category->tag_color) : null,
] : null, ] : null,
'fieldset' => ($assetmodel->fieldset) ? [ 'fieldset' => ($assetmodel->fieldset) ? [
'id' => (int) $assetmodel->fieldset->id, 'id' => (int) $assetmodel->fieldset->id,
@@ -70,7 +65,7 @@ class AssetModelsTransformer
'default_fieldset_values' => $default_field_values, 'default_fieldset_values' => $default_field_values,
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None', 'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
'requestable' => ($assetmodel->requestable == '1') ? true : false, 'requestable' => ($assetmodel->requestable == '1') ? true : false,
'require_serial' => ($assetmodel->require_serial == '1') ? true : false, 'require_serial' => $assetmodel->require_serial,
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes), 'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
'created_by' => ($assetmodel->adminuser) ? [ 'created_by' => ($assetmodel->adminuser) ? [
'id' => (int) $assetmodel->adminuser->id, 'id' => (int) $assetmodel->adminuser->id,

View File

@@ -40,6 +40,7 @@ class AssetsTransformer
] : null, ] : null,
'byod' => ($asset->byod ? true : false), 'byod' => ($asset->byod ? true : false),
'requestable' => ($asset->requestable ? true : false), 'requestable' => ($asset->requestable ? true : false),
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null, 'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => (($asset->asset_eol_date != '') && ($asset->purchase_date != '')) ? (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true) . ' months' : null, 'eol' => (($asset->asset_eol_date != '') && ($asset->purchase_date != '')) ? (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true) . ' months' : null,
'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null, 'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null,
@@ -52,12 +53,10 @@ class AssetsTransformer
'category' => (($asset->model) && ($asset->model->category)) ? [ 'category' => (($asset->model) && ($asset->model->category)) ? [
'id' => (int) $asset->model->category->id, 'id' => (int) $asset->model->category->id,
'name'=> e($asset->model->category->name), 'name'=> e($asset->model->category->name),
'tag_color'=> ($asset->model->category->tag_color) ? e($asset->model->category->tag_color) : null,
] : null, ] : null,
'manufacturer' => (($asset->model) && ($asset->model->manufacturer)) ? [ 'manufacturer' => (($asset->model) && ($asset->model->manufacturer)) ? [
'id' => (int) $asset->model->manufacturer->id, 'id' => (int) $asset->model->manufacturer->id,
'name'=> e($asset->model->manufacturer->name), 'name'=> e($asset->model->manufacturer->name),
'tag_color'=> ($asset->model->manufacturer->tag_color) ? e($asset->model->manufacturer->tag_color) : null,
] : null, ] : null,
'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? [ 'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? [
'id' => (int) $asset->model->depreciation->id, 'id' => (int) $asset->model->depreciation->id,
@@ -69,24 +68,20 @@ class AssetsTransformer
'supplier' => ($asset->supplier) ? [ 'supplier' => ($asset->supplier) ? [
'id' => (int) $asset->supplier->id, 'id' => (int) $asset->supplier->id,
'name'=> e($asset->supplier->name), 'name'=> e($asset->supplier->name),
'tag_color'=> ($asset->supplier->tag_color) ? e($asset->supplier->tag_color) : null,
] : null, ] : null,
'notes' => ($asset->notes) ? Helper::parseEscapedMarkedownInline($asset->notes) : null, 'notes' => ($asset->notes) ? Helper::parseEscapedMarkedownInline($asset->notes) : null,
'order_number' => ($asset->order_number) ? e($asset->order_number) : null, 'order_number' => ($asset->order_number) ? e($asset->order_number) : null,
'company' => ($asset->company) ? [ 'company' => ($asset->company) ? [
'id' => (int) $asset->company->id, 'id' => (int) $asset->company->id,
'name'=> e($asset->company->name), 'name'=> e($asset->company->name),
'tag_color'=> ($asset->company->tag_color) ? e($asset->company->tag_color) : null,
] : null, ] : null,
'location' => ($asset->location) ? [ 'location' => ($asset->location) ? [
'id' => (int) $asset->location->id, 'id' => (int) $asset->location->id,
'name'=> e($asset->location->name), 'name'=> e($asset->location->name),
'tag_color'=> ($asset->location->tag_color) ? e($asset->location->tag_color) : null,
] : null, ] : null,
'rtd_location' => ($asset->defaultLoc) ? [ 'rtd_location' => ($asset->defaultLoc) ? [
'id' => (int) $asset->defaultLoc->id, 'id' => (int) $asset->defaultLoc->id,
'name'=> e($asset->defaultLoc->name), 'name'=> e($asset->defaultLoc->name),
'tag_color'=> ($asset->defaultLoc->tag_color) ? e($asset->defaultLoc->tag_color) : null,
] : null, ] : null,
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null, 'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null, 'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null,

View File

@@ -66,7 +66,6 @@ class CategoriesTransformer
'id' => (int) $category->adminuser->id, 'id' => (int) $category->adminuser->id,
'name'=> e($category->adminuser->display_name), 'name'=> e($category->adminuser->display_name),
] : null, ] : null,
'tag_color' => $category->tag_color ? e($category->tag_color) : null,
'notes' => Helper::parseEscapedMarkedownInline($category->notes), 'notes' => Helper::parseEscapedMarkedownInline($category->notes),
'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'),

View File

@@ -40,7 +40,6 @@ class CompaniesTransformer
'id' => (int) $company->adminuser->id, 'id' => (int) $company->adminuser->id,
'name'=> e($company->adminuser->display_name), 'name'=> e($company->adminuser->display_name),
] : null, ] : null,
'tag_color' => ($company->tag_color!='') ? e($company->tag_color): null,
'notes' => Helper::parseEscapedMarkedownInline($company->notes), 'notes' => Helper::parseEscapedMarkedownInline($company->notes),
'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($company->updated_at, 'datetime'),

View File

@@ -30,25 +30,15 @@ class ComponentsTransformer
'location' => ($component->location) ? [ 'location' => ($component->location) ? [
'id' => (int) $component->location->id, 'id' => (int) $component->location->id,
'name' => e($component->location->name), 'name' => e($component->location->name),
'tag_color' => $component->location->tag_color ? e($component->location->tag_color) : null,
] : null, ] : null,
'qty' => ($component->qty != '') ? (int) $component->qty : null, 'qty' => ($component->qty != '') ? (int) $component->qty : null,
'min_amt' => ($component->min_amt != '') ? (int) $component->min_amt : null, 'min_amt' => ($component->min_amt != '') ? (int) $component->min_amt : null,
'category' => ($component->category) ? [ 'category' => ($component->category) ? [
'id' => (int) $component->category->id, 'id' => (int) $component->category->id,
'name' => e($component->category->name), 'name' => e($component->category->name),
'tag_color' => $component->category->tag_color ? e($component->category->tag_color) : null,
] : null,
'supplier' => ($component->supplier) ? [
'id' => $component->supplier->id,
'name'=> e($component->supplier->name),
'tag_color' => $component->supplier->tag_color ? e($component->supplier->tag_color) : null,
] : null,
'manufacturer' => ($component->manufacturer) ? [
'id' => $component->manufacturer->id,
'name'=> e($component->manufacturer->name),
'tag_color' => $component->manufacturer->tag_color ? e($component->manufacturer->tag_color) : null,
] : null, ] : null,
'supplier' => ($component->supplier) ? ['id' => $component->supplier->id, 'name'=> e($component->supplier->name)] : null,
'manufacturer' => ($component->manufacturer) ? ['id' => $component->manufacturer->id, 'name'=> e($component->manufacturer->name)] : null,
'model_number' => ($component->model_number) ? e($component->model_number) : null, 'model_number' => ($component->model_number) ? e($component->model_number) : null,
'order_number' => e($component->order_number), 'order_number' => e($component->order_number),
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'), 'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
@@ -58,7 +48,6 @@ class ComponentsTransformer
'company' => ($component->company) ? [ 'company' => ($component->company) ? [
'id' => (int) $component->company->id, 'id' => (int) $component->company->id,
'name' => e($component->company->name), 'name' => e($component->company->name),
'tag_color' => $component->company->tag_color ? e($component->company->tag_color) : null,
] : null, ] : null,
'notes' => ($component->notes) ? Helper::parseEscapedMarkedownInline($component->notes) : null, 'notes' => ($component->notes) ? Helper::parseEscapedMarkedownInline($component->notes) : null,
'created_by' => ($component->adminuser) ? [ 'created_by' => ($component->adminuser) ? [

View File

@@ -26,32 +26,12 @@ class ConsumablesTransformer
'id' => (int) $consumable->id, 'id' => (int) $consumable->id,
'name' => e($consumable->name), 'name' => e($consumable->name),
'image' => ($consumable->getImageUrl()) ? ($consumable->getImageUrl()) : null, 'image' => ($consumable->getImageUrl()) ? ($consumable->getImageUrl()) : null,
'category' => ($consumable->category) ? [ 'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null,
'id' => $consumable->category->id, 'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null,
'name' => e($consumable->category->name),
'tag_color' => $consumable->category->tag_color ? e($consumable->category->tag_color) : null,
] : null,
'company' => ($consumable->company) ? [
'id' => (int) $consumable->company->id,
'name' => e($consumable->company->name),
'tag_color' => $consumable->company->tag_color ? e($consumable->company->tag_color) : null,
] : null,
'item_no' => e($consumable->item_no), 'item_no' => e($consumable->item_no),
'location' => ($consumable->location) ? [ 'location' => ($consumable->location) ? ['id' => (int) $consumable->location->id, 'name' => e($consumable->location->name)] : null,
'id' => (int) $consumable->location->id, 'manufacturer' => ($consumable->manufacturer) ? ['id' => (int) $consumable->manufacturer->id, 'name' => e($consumable->manufacturer->name)] : null,
'name' => e($consumable->location->name), 'supplier' => ($consumable->supplier) ? ['id' => $consumable->supplier->id, 'name'=> e($consumable->supplier->name)] : null,
'tag_color' => $consumable->location->tag_color ? e($consumable->location->tag_color) : null,
] : null,
'manufacturer' => ($consumable->manufacturer) ? [
'id' => (int) $consumable->manufacturer->id,
'name' => e($consumable->manufacturer->name),
'tag_color' => $consumable->manufacturer->tag_color ? e($consumable->manufacturer->tag_color) : null,
] : null,
'supplier' => ($consumable->supplier) ? [
'id' => $consumable->supplier->id,
'name'=> e($consumable->supplier->name),
'tag_color' => $consumable->supplier->tag_color ? e($consumable->supplier->tag_color) : null,
] : null,
'min_amt' => (int) $consumable->min_amt, 'min_amt' => (int) $consumable->min_amt,
'model_number' => ($consumable->model_number != '') ? e($consumable->model_number) : null, 'model_number' => ($consumable->model_number != '') ? e($consumable->model_number) : null,
'remaining' => $consumable->numRemaining(), 'remaining' => $consumable->numRemaining(),

View File

@@ -32,7 +32,6 @@ class DepartmentsTransformer
'company' => ($department->company) ? [ 'company' => ($department->company) ? [
'id' => (int) $department->company->id, 'id' => (int) $department->company->id,
'name'=> e($department->company->name), 'name'=> e($department->company->name),
'tag_color' => $department->company->tag_color ? e($department->company->tag_color) : null,
] : null, ] : null,
'manager' => ($department->manager) ? [ 'manager' => ($department->manager) ? [
'id' => (int) $department->manager->id, 'id' => (int) $department->manager->id,
@@ -43,10 +42,8 @@ class DepartmentsTransformer
'location' => ($department->location) ? [ 'location' => ($department->location) ? [
'id' => (int) $department->location->id, 'id' => (int) $department->location->id,
'name' => e($department->location->name), 'name' => e($department->location->name),
'tag_color' => $department->location->tag_color ? e($department->location->tag_color) : null,
] : null, ] : null,
'users_count' => (int) ($department->users_count), 'users_count' => e($department->users_count),
'tag_color' => $department->tag_color ? e($department->tag_color) : null,
'notes' => Helper::parseEscapedMarkedownInline($department->notes), 'notes' => Helper::parseEscapedMarkedownInline($department->notes),
'created_at' => Helper::getFormattedDateObject($department->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($department->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($department->updated_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($department->updated_at, 'datetime'),

View File

@@ -34,16 +34,8 @@ class LicenseSeatsTransformer
[ [
'id' => (int) $seat->user->department->id, 'id' => (int) $seat->user->department->id,
'name' => e($seat->user->department->name), 'name' => e($seat->user->department->name),
'tag_color' => $seat->user->department->tag_color ? e($seat->user->department->tag_color) : null,
] : null, ] : null,
'company'=> ($seat->user->company) ?
[
'id' => (int) $seat->user->company->id,
'name' => e($seat->user->company->name),
'tag_color' => $seat->user->company->tag_color ? e($seat->user->company->tag_color) : null,
] : null,
'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'),
] : null, ] : null,
'assigned_asset' => ($seat->asset) ? [ 'assigned_asset' => ($seat->asset) ? [
@@ -54,7 +46,6 @@ class LicenseSeatsTransformer
'location' => ($seat->location()) ? [ 'location' => ($seat->location()) ? [
'id' => (int) $seat->location()->id, 'id' => (int) $seat->location()->id,
'name'=> e($seat->location()->name), 'name'=> e($seat->location()->name),
'tag_color' => $seat->location()->tag_color ? e($seat->location()->tag_color) : null,
'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($seat->created_at, 'datetime'),
] : null, ] : null,
'reassignable' => (bool) $seat->license->reassignable, 'reassignable' => (bool) $seat->license->reassignable,

View File

@@ -25,11 +25,7 @@ class LicensesTransformer
'id' => (int) $license->id, 'id' => (int) $license->id,
'name' => e($license->name), 'name' => e($license->name),
'company' => ($license->company) ? ['id' => (int) $license->company->id, 'name'=> e($license->company->name)] : null, 'company' => ($license->company) ? ['id' => (int) $license->company->id, 'name'=> e($license->company->name)] : null,
'manufacturer' => ($license->manufacturer) ? [ 'manufacturer' => ($license->manufacturer) ? ['id' => (int) $license->manufacturer->id, 'name'=> e($license->manufacturer->name)] : null,
'id' => (int) $license->manufacturer->id,
'name'=> e($license->manufacturer->name),
'tag_color'=> ($license->manufacturer->tag_color) ? e($license->manufacturer->tag_color) : null,
] : null,
'product_key' => (Gate::allows('viewKeys', License::class)) ? e($license->serial) : '------------', 'product_key' => (Gate::allows('viewKeys', License::class)) ? e($license->serial) : '------------',
'order_number' => ($license->order_number) ? e($license->order_number) : null, 'order_number' => ($license->order_number) ? e($license->order_number) : null,
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null, 'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
@@ -48,16 +44,8 @@ class LicensesTransformer
'license_email' => ($license->license_email) ? e($license->license_email) : null, 'license_email' => ($license->license_email) ? e($license->license_email) : null,
'reassignable' => ($license->reassignable == 1) ? true : false, 'reassignable' => ($license->reassignable == 1) ? true : false,
'maintained' => ($license->maintained == 1) ? true : false, 'maintained' => ($license->maintained == 1) ? true : false,
'supplier' => ($license->supplier) ? [ 'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id, 'name'=> e($license->supplier->name)] : null,
'id' => (int) $license->supplier->id, 'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null,
'name'=> e($license->supplier->name),
'tag_color'=> ($license->supplier->tag_color) ? e($license->supplier->tag_color) : null,
] : null,
'category' => ($license->category) ? [
'id' => (int) $license->category->id,
'name'=> e($license->category->name),
'tag_color'=> ($license->category->tag_color) ? e($license->category->tag_color) : null,
] : null,
'created_by' => ($license->adminuser) ? [ 'created_by' => ($license->adminuser) ? [
'id' => (int) $license->adminuser->id, 'id' => (int) $license->adminuser->id,
'name'=> e($license->adminuser->display_name), 'name'=> e($license->adminuser->display_name),

View File

@@ -58,7 +58,6 @@ class LocationsTransformer
'children_count' => (int) $location->children_count, 'children_count' => (int) $location->children_count,
'currency' => ($location->currency) ? e($location->currency) : null, 'currency' => ($location->currency) ? e($location->currency) : null,
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null, 'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
'tag_color' => $location->tag_color ? e($location->tag_color) : null,
'notes' => Helper::parseEscapedMarkedownInline($location->notes), 'notes' => Helper::parseEscapedMarkedownInline($location->notes),
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
'created_by' => $location->adminuser ? [ 'created_by' => $location->adminuser ? [
@@ -69,13 +68,11 @@ class LocationsTransformer
'parent' => ($location->parent) ? [ 'parent' => ($location->parent) ? [
'id' => (int) $location->parent->id, 'id' => (int) $location->parent->id,
'name'=> e($location->parent->name), 'name'=> e($location->parent->name),
'tag_color' => $location->parent->tag_color ? e($location->parent->tag_color) : null,
] : null, ] : null,
'manager' => ($location->manager) ? (new UsersTransformer)->transformUser($location->manager) : null, 'manager' => ($location->manager) ? (new UsersTransformer)->transformUser($location->manager) : null,
'company' => ($location->company) ? [ 'company' => ($location->company) ? [
'id' => (int) $location->company->id, 'id' => (int) $location->company->id,
'name'=> e($location->company->name), 'name'=> e($location->company->name)
'tag_color' => $location->company->tag_color ? e($location->company->tag_color) : null,
] : null, ] : null,
'children' => $children_arr, 'children' => $children_arr,

View File

@@ -66,7 +66,6 @@ class MaintenancesTransformer
'id' => $assetmaintenance->supplier->id, 'id' => $assetmaintenance->supplier->id,
'name'=> e($assetmaintenance->supplier->name) 'name'=> e($assetmaintenance->supplier->name)
] : null, ] : null,
'url' => ($assetmaintenance->url) ? e($assetmaintenance->url) : null,
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost), 'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type), 'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type),
'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'), 'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'),

View File

@@ -37,7 +37,6 @@ class ManufacturersTransformer
'consumables_count' => (int) $manufacturer->consumables_count, 'consumables_count' => (int) $manufacturer->consumables_count,
'accessories_count' => (int) $manufacturer->accessories_count, 'accessories_count' => (int) $manufacturer->accessories_count,
'components_count' => (int) $manufacturer->components_count, 'components_count' => (int) $manufacturer->components_count,
'tag_color' => $manufacturer->tag_color ? e($manufacturer->tag_color) : null,
'notes' => Helper::parseEscapedMarkedownInline($manufacturer->notes), 'notes' => Helper::parseEscapedMarkedownInline($manufacturer->notes),
'created_by' => ($manufacturer->adminuser) ? [ 'created_by' => ($manufacturer->adminuser) ? [
'id' => (int) $manufacturer->adminuser->id, 'id' => (int) $manufacturer->adminuser->id,

View File

@@ -26,7 +26,6 @@ class SelectlistTransformer
'id' => (int) $select_item->id, 'id' => (int) $select_item->id,
'text' => ($select_item->use_text) ? $select_item->use_text : $select_item->name, 'text' => ($select_item->use_text) ? $select_item->use_text : $select_item->name,
'image' => ($select_item->use_image) ? $select_item->use_image : null, 'image' => ($select_item->use_image) ? $select_item->use_image : null,
'tag_color' => ($select_item->tag_color) ? $select_item->tag_color : null,
]; ];
} }

View File

@@ -43,7 +43,6 @@ class SuppliersTransformer
'licenses_count' => (int) $supplier->licenses_count, 'licenses_count' => (int) $supplier->licenses_count,
'consumables_count' => (int) $supplier->consumables_count, 'consumables_count' => (int) $supplier->consumables_count,
'components_count' => (int) $supplier->components_count, 'components_count' => (int) $supplier->components_count,
'tag_color' => $supplier->tag_color ? e($supplier->tag_color) : null,
'notes' => ($supplier->notes) ? Helper::parseEscapedMarkedownInline($supplier->notes) : null, 'notes' => ($supplier->notes) ? Helper::parseEscapedMarkedownInline($supplier->notes) : null,
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'), 'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
'created_by' => $supplier->adminuser ? [ 'created_by' => $supplier->adminuser ? [

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