Compare commits

..

6 Commits

Author SHA1 Message Date
snipe 172942878b Added checkin as option in dropdown actions
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:20:13 -08:00
snipe 46279c5f3d Small layout fix
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:56 -08:00
snipe 731dc29bf5 New checkin blade
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:48 -08:00
snipe 530a76881e Added language strings
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:42 -08:00
snipe 257a501d70 Added routing logic for what form should be displayed
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:34 -08:00
snipe e047d5516c Added new bulk checkin routes
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:16 -08:00
1518 changed files with 303438 additions and 22415 deletions
-81
View File
@@ -2585,87 +2585,6 @@
"contributions": [
"code"
]
},
{
"login": "QveenSi",
"name": "Yevhenii Huzii",
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
"profile": "https://github.com/QveenSi",
"contributions": [
"code"
]
},
{
"login": "veenone",
"name": "Achmad Fienan Rahardianto",
"avatar_url": "https://avatars.githubusercontent.com/u/3839381?v=4",
"profile": "https://github.com/veenone",
"contributions": [
"code"
]
},
{
"login": "QveenSi",
"name": "Yevhenii Huzii",
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
"profile": "https://github.com/QveenSi",
"contributions": [
"code"
]
},
{
"login": "chrisweirich",
"name": "Christian Weirich",
"avatar_url": "https://avatars.githubusercontent.com/u/97299851?v=4",
"profile": "https://github.com/chrisweirich",
"contributions": [
"code"
]
},
{
"login": "denzfarid",
"name": "denzfarid",
"avatar_url": "https://avatars.githubusercontent.com/u/1294403?v=4",
"profile": "https://github.com/denzfarid",
"contributions": []
},
{
"login": "ntbutler-nbcs",
"name": "ntbutler-nbcs",
"avatar_url": "https://avatars.githubusercontent.com/u/94018771?v=4",
"profile": "https://github.com/ntbutler-nbcs",
"contributions": [
"code"
]
},
{
"login": "naveensrinivasan",
"name": "Naveen",
"avatar_url": "https://avatars.githubusercontent.com/u/172697?v=4",
"profile": "https://naveensrinivasan.dev",
"contributions": [
"code"
]
},
{
"login": "mikeroq",
"name": "Mike Roquemore",
"avatar_url": "https://avatars.githubusercontent.com/u/55674383?v=4",
"profile": "https://github.com/mikeroq",
"contributions": [
"code"
]
},
{
"login": "reederda",
"name": "Daniel Reeder",
"avatar_url": "https://avatars.githubusercontent.com/u/7991086?v=4",
"profile": "https://github.com/reederda",
"contributions": [
"translations",
"translation",
"code"
]
}
]
}
-7
View File
@@ -138,13 +138,6 @@ PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null
PRIVATE_AWS_BUCKET_ROOT=null
# --------------------------------------------
# OPTIONAL: AWS Settings
# --------------------------------------------
AWS_ACCESS_KEY_ID=null
AWS_SECRET_ACCESS_KEY=null
AWS_DEFAULT_REGION=null
# --------------------------------------------
# OPTIONAL: LOGIN THROTTLING
# --------------------------------------------
+4 -18
View File
@@ -70,13 +70,11 @@ IMAGE_LIB=gd
MAIL_BACKUP_NOTIFICATION_DRIVER=null
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
BACKUP_ENV=true
ALLOW_BACKUP_DELETE=false
ALLOW_DATA_PURGE=false
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_DRIVER=file
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=false
@@ -99,6 +97,7 @@ ENABLE_HSTS=false
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
CACHE_PREFIX=snipeit
@@ -135,25 +134,12 @@ PRIVATE_AWS_BUCKET=null
PRIVATE_AWS_URL=null
PRIVATE_AWS_BUCKET_ROOT=null
# --------------------------------------------
# OPTIONAL: AWS Settings
# --------------------------------------------
AWS_ACCESS_KEY_ID=null
AWS_SECRET_ACCESS_KEY=null
AWS_DEFAULT_REGION=null
# --------------------------------------------
# OPTIONAL: LOGIN THROTTLING
# --------------------------------------------
LOGIN_MAX_ATTEMPTS=5
LOGIN_LOCKOUT_DURATION=60
# --------------------------------------------
# OPTIONAL: FORGOTTEN PASSWORD SETTINGS
# --------------------------------------------
RESET_PASSWORD_LINK_EXPIRES=15
PASSWORD_CONFIRM_TIMEOUT=10800
PASSWORD_RESET_MAX_ATTEMPTS_PER_MIN=50
RESET_PASSWORD_LINK_EXPIRES=900
# --------------------------------------------
# OPTIONAL: MISC
@@ -171,4 +157,4 @@ IMPORT_TIME_LIMIT=600
IMPORT_MEMORY_LIMIT=500M
REPORT_TIME_LIMIT=12000
REQUIRE_SAML=false
API_THROTTLE_PER_MINUTE=120
+1 -1
View File
@@ -38,7 +38,7 @@ IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: AWS SETTINGS
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET_ACCESS_KEY=null
AWS_ACCESS_KEY_ID=null
+1 -1
View File
@@ -15,8 +15,8 @@
# *.js @octocat @github/js
app/Importer/* @dmeltzer
app/Http/Controllers/CustomFields* @uberbrady
app/Http/Controllers/Api/CustomFields* @uberbrady
resources/views/custom_fields/* @uberbrady
docker/* @uberbrady
app/Providers/SamlServiceProvider.php @uberbrady
+42 -27
View File
@@ -1,27 +1,42 @@
name: Feature Request
description: Suggest an idea for this project
title: "[Feature Request]: "
labels: ["feature request"]
assignees:
- snipe
body:
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. The more information you can provide about your use-case, the more liklely we are to consider your feature.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
name: Feature Request
description: Suggest an idea for this project
body:
- type: input
attributes:
label: Snipe-IT Version
validations:
required: true
- type: input
id: server_operatingSystem
attributes:
label: Operating System
description: 'e.g. Ubuntu, Windows'
validations:
required: true
- type: input
attributes:
label: Web Server
description: 'e.g. Apache, IIS'
validations:
required: true
- type: input
attributes:
label: PHP Version
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional context Add any other context or screenshots about the feature request here.
+3 -17
View File
@@ -1,18 +1,4 @@
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*", "*livewire*"]
skins: ["*.js", "*.css", "*.scss", "*.less"]
css: ["*.css","*.scss", "*.less"]
backend: ["/app/*", "*.php"]
backups: ["*backup*"]
restore: ["*restore*"]
saml: ["*saml*"]
scim: ["*scim*"]
custom fields: ["*fields*", "*fieldsets*"]
dependencies: ["composer.json"]
consumables: ["*consumables*"]
api: ["/app/Http/Controllers/api/*"]
notifications: ["/app/Notifications/*"]
importer: ["/app/Importer/*"]
cli / artisan: ["/app/Console/*"]
LDAP: ["*LDAP*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
frontend: ["*.js", "*.css", "*.vue", "*.scss", "*.less", "*.blade.*"]
backend: ["/app", "*.php"]
legal: ["LICENSE*", "NOTICES*"]
config: .github
-6
View File
@@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
-39
View File
@@ -1,39 +0,0 @@
# This workflow checks out code, performs a CodeQL analysis (for JavaScript) and integrates the results
# with the GitHub Advanced Security code scanning feature.
# More information: https://codeql.github.com/
name: CodeQL Security Scan
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
# schedule:
# - cron: '15 17 * * 1'
jobs:
analyze:
name: CodeQL Security Scan
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+2 -10
View File
@@ -17,16 +17,8 @@ on:
schedule:
- cron: '36 23 * * 3'
permissions:
contents: read
jobs:
codacy-security-scan:
# Ensure schedule job never runs on forked repos. It's only executed for 'snipe/snipe-it'
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
if: (github.repository == 'snipe/snipe-it') || ((github.repository != 'snipe/snipe-it') && (github.event_name != 'schedule'))
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
@@ -36,7 +28,7 @@ jobs:
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@v4.1.0
uses: codacy/codacy-analysis-cli-action@1.1.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
@@ -52,6 +44,6 @@ jobs:
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: results.sarif
+4 -7
View File
@@ -15,9 +15,6 @@ on:
pull_request:
permissions:
contents: read
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
@@ -45,13 +42,13 @@ jobs:
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v1
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
@@ -63,7 +60,7 @@ jobs:
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v4
uses: docker/metadata-action@v3
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
@@ -72,7 +69,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v3
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.alpine
+4 -7
View File
@@ -15,9 +15,6 @@ on:
pull_request:
permissions:
contents: read
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'snipe/snipe-it'
@@ -45,13 +42,13 @@ jobs:
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v1
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
@@ -63,7 +60,7 @@ jobs:
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v4
uses: docker/metadata-action@v3
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
@@ -72,7 +69,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v3
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
-2
View File
@@ -23,7 +23,6 @@ php7.4-xml \
php7.4-mbstring \
php7.4-zip \
php7.4-bcmath \
php7.4-redis \
patch \
curl \
wget \
@@ -42,7 +41,6 @@ libmcrypt-dev \
php7.4-dev \
ca-certificates \
unzip \
dnsutils \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
-1
View File
@@ -27,7 +27,6 @@ RUN apk add --no-cache \
php7-xmlwriter \
php7-xmlreader \
php7-sodium \
php7-redis \
curl \
wget \
vim \
+3 -5
View File
@@ -1,11 +1,11 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-292-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-284-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
It is built on [Laravel 8](http://laravel.com).
It is built on [Laravel 6](http://laravel.com).
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
@@ -65,7 +65,6 @@ Since the release of the JSON REST API, several third-party developers have been
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@RodneyLeeBrands](https://github.com/RodneyLeeBrands) - Python script to synchronize information between Mosyle and Snipe-IT
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
@@ -132,8 +131,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") |
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") |
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -1,97 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Helpers\Helper;
use Illuminate\Console\Command;
use App\Models\User;
use Laravel\Passport\TokenRepository;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use DB;
class GeneratePersonalAccessToken extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:make-api-key
{--user_id= : The ID of the user to create the token for.}
{--name= : The name of the new API token}
{--key-only : Only return the value of the API key}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This console command allows you to generate Personal API tokens to be used with the Snipe-IT JSON REST API on behalf of a user.';
/**
* The token repository implementation.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
{
$this->validation = $validation;
$this->tokenRepository = $tokenRepository;
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$accessTokenName = $this->option('name');
if ($accessTokenName=='') {
$accessTokenName = 'CLI Auth Token';
}
if ($this->option('user_id')=='') {
return $this->error('ERROR: user_id cannot be blank.');
}
if ($user = User::find($this->option('user_id'))) {
$createAccessToken = $user->createToken($accessTokenName)->accessToken;
if ($this->option('key-only')) {
$this->info($createAccessToken);
} else {
$this->warn('Your API Token has been created. Be sure to copy this token now, as it will not be accessible again.');
if ($token = DB::table('oauth_access_tokens')->where('user_id', '=', $user->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first()) {
$this->info('API Token ID: '.$token->id);
}
$this->info('API Token User: '.$user->present()->fullName.' ('.$user->username.')');
$this->info('API Token Name: '.$accessTokenName);
$this->info('API Token: '.$createAccessToken);
}
} else {
return $this->error('ERROR: Invalid user. API key was not created.');
}
}
}
-59
View File
@@ -1,59 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class KillAllSessions extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:global-logout {--force : Skip the danger prompt; assuming you enter "y"} ';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will destroy all web sessions on disk and will force a re-login for all users.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (!$this->option('force') && !$this->confirm("****************************************************\nTHIS WILL FORCE A LOGIN FOR ALL LOGGED IN USERS.\n\nAre you SURE you wish to continue? ")) {
return $this->error("Session loss not confirmed");
}
$session_files = glob(storage_path("framework/sessions/*"));
$count = 0;
foreach ($session_files as $file) {
if (is_file($file))
unlink($file);
$count++;
}
\DB::table('users')->update(['remember_token' => null]);
$this->info($count. ' sessions cleared!');
}
}
+4 -20
View File
@@ -17,7 +17,7 @@ class LdapSync extends Command
*
* @var string
*/
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--filter=} {--summary} {--json_summary}';
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--summary} {--json_summary}';
/**
* The console command description.
@@ -56,7 +56,6 @@ class LdapSync extends Command
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
$ldap_result_country = Setting::getSettings()->ldap_country;
$ldap_result_dept = Setting::getSettings()->ldap_dept;
$ldap_result_manager = Setting::getSettings()->ldap_manager;
try {
$ldapconn = Ldap::connectToLdap();
@@ -80,11 +79,7 @@ class LdapSync extends Command
} else {
$search_base = null;
}
if ($this->option('filter') != '') {
$results = Ldap::findLdapUsers($search_base, -1, $this->option('filter'));
} else {
$results = Ldap::findLdapUsers($search_base);
}
$results = Ldap::findLdapUsers($search_base);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
@@ -113,7 +108,7 @@ class LdapSync extends Command
}
/* Process locations with explicitly defined OUs, if doing a full import. */
if ($this->option('base_dn') == '' && $this->option('filter') == '') {
if ($this->option('base_dn') == '') {
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
$ldap_ou_lengths = [];
@@ -189,12 +184,12 @@ class LdapSync extends Command
$item['jobtitle'] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : '';
$item['country'] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : '';
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
$item['manager'] = isset($results[$i][$ldap_result_manager][0]) ? $results[$i][$ldap_result_manager][0] : '';
$department = Department::firstOrCreate([
'name' => $item['department'],
]);
$user = User::where('username', $item['username'])->first();
if ($user) {
// Updating an existing user.
@@ -217,17 +212,6 @@ class LdapSync extends Command
$user->country = $item['country'];
$user->department_id = $department->id;
if($item['manager'] != null) {
//Captures only the Canonical Name
$item['manager'] = ltrim($item['manager'], "CN=");
$item['manager'] = substr($item['manager'],0, strpos($item['manager'], ','));
$ldap_manager = User::where('username', $item['manager'])->first();
if ( $ldap_manager && isset($ldap_manager->id) ) {
$user->manager_id = $ldap_manager->id;
}
}
// Sync activated state for Active Directory.
if (array_key_exists('useraccountcontrol', $results[$i])) {
/* The following is _probably_ the correct logic, but we can't use it because
-517
View File
@@ -1,517 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Setting;
use Exception;
use Crypt;
/**
* Check if a given ip is in a network
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
* @return boolean true if the ip is in this range / false if not.
*/
function ip_in_range( $ip, $range ) {
if ( strpos( $range, '/' ) == false ) {
$range .= '/32';
}
// $range is in IP/CIDR format eg 127.0.0.1/24
list( $range, $netmask ) = explode( '/', $range, 2 );
$range_decimal = ip2long( $range );
$ip_decimal = ip2long( $ip );
$wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
}
// NOTE - this function was shamelessly stolen from this gist: https://gist.github.com/tott/7684443
/**
* Ensure LDAP filters are parentheses-wrapped
*/
function parenthesized_filter($filter)
{
if(substr($filter,0,1) == "(" ) {
return $filter;
} else {
return "(".$filter.")";
}
}
class LdapTroubleshooter extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ldap:troubleshoot
{--ldap-search : Output an ldapsearch command-line for testing your LDAP config}
{--force : Skip the interactive yes/no prompt for confirmation}
{--debug : Include debugging output (verbose)}
{--trace : Include extremely verbose LDAP trace output}
{--timeout=15 : Timeout for LDAP Bind operations}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Runs a series of non-destructive LDAP commands to help try and determine correct LDAP settings for your environment.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Output something *only* if debug is enabled
*
* @return void
*/
public function debugout($string)
{
if($this->option('debug')) {
$this->line($string);
}
}
/**
* Clean the results from ldap_get_entries into something useful
* @param array $array
* @return array
*/
public function ldap_results_cleaner ($array) {
$cleaned = [];
for($i = 0; $i < $array['count']; $i++) {
$row = $array[$i];
$clean_row = [];
foreach($row AS $key => $val ) {
$this->debugout("Key is: ".$key);
if($key == "count" || is_int($key) || $key == "dn") {
$this->debugout(" and we're gonna skip it\n");
continue;
}
$this->debugout(" And that seems fine.\n");
if(array_key_exists('count',$val)) {
if($val['count'] == 1) {
$clean_row[$key] = $val[0];
} else {
unset($val['count']); //these counts are annoying
$elements = [];
foreach($val as $entry) {
if(isset($ldap_constants[$entry])) {
$elements[] = $ldap_constants[$entry];
} else {
$elements[] = $entry;
}
}
$clean_row[$key] = $elements;
}
} else {
$clean_row[$key] = $val;
}
}
$cleaned[$i] = $clean_row;
}
return $cleaned;
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if($this->option('trace')) {
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
}
$settings = Setting::getSettings();
$this->settings = $settings;
if($this->option('ldap-search')) {
if(!$this->option('force')) {
$confirmation = $this->confirm('WARNING: This command will display your LDAP password on your terminal. Are you sure this is ok?');
if(!$confirmation) {
$this->error('ABORTING');
exit(-1);
}
}
$output = [];
if($settings->ldap_server_cert_ignore) {
$this->line("# Ignoring server certificate validity");
$output[] = "LDAPTLS_REQCERT=never";
}
if($settings->ldap_client_tls_cert && $settings->ldap_client_tls_key) {
$this->line("# Adding LDAP Client Certificate and Key");
$output[] = "LDAPTLS_CERT=storage/ldap_client_tls.cert";
$output[] = "LDAPTLS_KEY=storage/ldap_client_tls.key";
}
$output[] = "ldapsearch";
$output[] = "-H ".$settings->ldap_server;
$output[] = "-x";
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
$output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter));
if($settings->ldap_tls) {
$this->line("# adding STARTTLS option");
$output[] = "-Z";
}
$output[] = "-v";
$this->line("\n");
$this->line(implode(" \\\n",$output));
exit(0);
}
if(!$this->option('force')) {
$confirmation = $this->confirm('WARNING: This command will make several attempts to connect to your LDAP server. Are you sure this is ok?');
if(!$confirmation) {
$this->error('ABORTING');
exit(-1);
}
}
//$this->line(print_r($settings,true));
$this->info("STAGE 1: Checking settings");
if(!$settings->ldap_enabled) {
$this->error("WARNING: Snipe-IT's LDAP setting is not turned on. (That may be OK if you're still trying to figure out settings)");
}
$ldap_conn = false;
try {
$ldap_conn = ldap_connect($settings->ldap_server);
} catch (Exception $e) {
$this->error("WARNING: Exception caught when executing 'ldap_connect()' - ".$e->getMessage().". We will try to guess.");
}
if(!$ldap_conn) {
$this->error("WARNING: LDAP Server setting of: ".$settings->ldap_server." cannot be parsed. We will try to guess.");
//exit(-1);
}
//since we never use $ldap_conn again, we don't have to ldap_unbind() it (it's not even connected, tbh - that only happens at bind-time)
$parsed = parse_url($settings->ldap_server);
if(@$parsed['scheme'] != 'ldap' && @$parsed['scheme'] != 'ldaps') {
$this->error("WARNING: LDAP URL Scheme of '".@$parsed['scheme']."' is probably incorrect; should usually be ldap or ldaps");
}
if(!@$parsed['host']) {
$this->error("ERROR: Cannot determine hostname or IP from ldap URL: ".$settings->ldap_server.". ABORTING.");
exit(-1);
} else {
$this->info("Determined LDAP hostname to be: ".$parsed['host']);
}
$this->info("Performing DNS lookup of: ".$parsed['host']);
$ips = dns_get_record($parsed['host']);
$raw_ips = [];
//$this->info("Host IP is: ".print_r($ips,true));
if(!$ips || count($ips) == 0) {
$this->error("ERROR: DNS lookup of host: ".$parsed['host']." has failed. ABORTING.");
exit(-1);
}
$this->debugout("IP's? ".print_r($ips,true));
foreach($ips as $ip) {
if(!isset($ip['ip'])) {
continue;
}
$raw_ips[]=$ip['ip'];
if($ip['ip'] == "127.0.0.1") {
$this->error("WARNING: Using the localhost IP as the LDAP server. This is usually wrong");
}
if(ip_in_range($ip['ip'],'10.0.0.0/8') || ip_in_range($ip['ip'],'192.168.0.0/16') || ip_in_range($ip['ip'], '172.16.0.0/12')) {
$this->error("WARNING: Using an RFC1918 Private address for LDAP server. This may be correct, but it can be a problem if your Snipe-IT instance is not hosted on your private network");
}
}
$this->info("STAGE 2: Checking basic network connectivity");
$ports = [389,636];
if(@$parsed['port'] && !in_array($parsed['port'],$ports)) {
$ports[] = $parsed['port'];
}
$open_ports=[];
foreach($ports as $port ) {
$errno = 0;
$errstr = '';
$timeout = 30.0;
$result = '';
$this->info("Attempting to connect to port: ".$port." - may take up to $timeout seconds");
try {
$result = fsockopen($parsed['host'], $port, $errno, $errstr, 30.0);
} catch(Exception $e) {
$this->error("Exception: ".$e->getMessage());
}
if($result) {
$this->info("Success!");
$open_ports[] = $port;
} else {
$this->error("WARNING: Cannot connect to port: $port - $errstr ($errno)");
}
}
if(count($open_ports) == 0) {
$this->error("ERROR - no open ports. ABORTING.");
exit(-1);
}
$this->info("STAGE 3: Determine encryption algorithm, if any");
$ldap_urls = [];
$pretty_ldap_urls = [];
foreach($open_ports as $port) {
$this->line("Trying TLS first for port $port");
$ldap_url = "ldaps://".$parsed['host'].":$port";
if($this->test_anonymous_bind($ldap_url)) {
$this->info("Anonymous bind succesful to $ldap_url!");
$ldap_urls[] = [ $ldap_url, true, false ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
continue; // TODO - lots of copypasta in these if(test_anonymous_bind()) routines...
} else {
$this->error("WARNING: Failed to bind to $ldap_url - trying without certificate checks.");
}
if($this->test_anonymous_bind($ldap_url, false)) {
$this->info("Anonymous bind succesful to $ldap_url with certifcate-checks disabled");
$ldap_urls[] = [ $ldap_url, false, false ];
$pretty_ldap_urls[] = [ $ldap_url, "no", "no" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url with certificate checks disabled. Trying unencrypted with STARTTLS");
}
$ldap_url = "ldap://".$parsed['host'].":$port";
if($this->test_anonymous_bind($ldap_url, true, true)) {
$this->info("Plain connection to $ldap_url with STARTTLS succesful!");
$ldap_urls[] = [ $ldap_url, true, true ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "YES" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled. Trying without STARTTLS");
}
if($this->test_anonymous_bind($ldap_url)) {
$this->info("Plain connection to $ldap_url succesful!");
$ldap_urls[] = [ $ldap_url, true, false ];
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
continue;
} else {
$this->error("WARNING: Failed to bind to $ldap_url. Giving up on port $port");
}
}
$this->debugout(print_r($ldap_urls,true));
if(count($ldap_urls) > 0 ) {
$this->info("Found working LDAP URL's: ");
foreach($ldap_urls as $ldap_url) { // TODO maybe do this as a $this->table() instead?
$this->info("LDAP URL: ".$ldap_url[0]);
$this->info($ldap_url[0]. ($ldap_url[1] ? " certificate checks enabled" : " certificate checks disabled"). ($ldap_url[2] ? " STARTTLS Enabled ": " STARTTLS Disabled"));
}
$this->table(["URL", "Cert Checks Enabled?", "STARTTLS Enabled?"],$pretty_ldap_urls);
} else {
$this->error("ERROR - no valid LDAP URL's available - ABORTING");
exit(1);
}
$this->info("STAGE 4: Test Administrative Bind for LDAP Sync");
foreach($ldap_urls AS $ldap_url) {
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, Crypt::decrypt($settings->ldap_pword));
}
$this->info("STAGE 5: Test BaseDN");
//grab all LDAP_ constants and fill up a reversed array mapping from weird LDAP dotted-strings to (Constant Name)
$all_defined_constants = get_defined_constants();
$ldap_constants = [];
foreach($all_defined_constants AS $key => $val) {
if(starts_with($key,"LDAP_") && is_string($val)) {
$ldap_constants[$val] = $key; // INVERT the meaning here!
}
}
$this->debugout("LDAP constants are: ".print_r($ldap_constants,true));
foreach($ldap_urls AS $ldap_url) {
if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword),$settings)) {
$this->info("Success getting informational bind!");
} else {
$this->error("Unable to get information from bind.");
}
}
$this->info("STAGE 6: Test LDAP Login to Snipe-IT");
foreach($ldap_urls AS $ldap_url) {
$this->info("Starting auth to ".$ldap_url[0]);
while(true) {
$with_tls = $ldap_url[1] ? "with": "without";
$with_startssl = $ldap_url[2] ? "using": "not using";
if(!$this->confirm('Do you wish to try to authenticate to this directory: '.$ldap_url[0]." $with_tls TLS and $with_startssl STARTSSL?")) {
break;
}
$username = $this->ask("Username");
$password = $this->secret("Password");
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results?
}
}
$this->info("LDAP TROUBLESHOOTING COMPLETE!");
}
public function connect_to_ldap($ldap_url, $check_cert, $start_tls)
{
$lconn = ldap_connect($ldap_url);
ldap_set_option($lconn, LDAP_OPT_PROTOCOL_VERSION, 3); // should we 'test' different protocol versions here? Does anyone even use anything other than LDAPv3?
// no - it's formally deprecated: https://tools.ietf.org/html/rfc3494
if(!$check_cert) {
putenv('LDAPTLS_REQCERT=never'); // This is horrible; is this *really* the only way to do it?
} else {
putenv('LDAPTLS_REQCERT'); // have to very explicitly and manually *UN* set the env var here to ensure it works
}
if($this->settings->ldap_client_tls_cert && $this->settings->ldap_client_tls_key) {
// client-side TLS certificate support for LDAP (Google Secure LDAP)
putenv('LDAPTLS_CERT=storage/ldap_client_tls.cert');
putenv('LDAPTLS_KEY=storage/ldap_client_tls.key');
}
if($start_tls) {
if(!ldap_start_tls($lconn)) {
$this->error("WARNING: Unable to start TLS");
return false;
}
}
if(!$lconn) {
$this->error("WARNING: Failed to generate connection string - using: ".$ldap_url);
return false;
}
$net = ldap_set_option($lconn, LDAP_OPT_NETWORK_TIMEOUT, $this->option('timeout'));
$time = ldap_set_option($lconn, LDAP_OPT_TIMELIMIT, $this->option('timeout'));
if(!$net || !$time) {
$this->error("Unable to set timeouts!");
}
return $lconn;
}
public function test_anonymous_bind($ldap_url, $check_cert = true, $start_tls = false)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert , $start_tls) {
try {
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$this->info("gonna try to bind now, this can take a while if we mess it up");
$bind_results = ldap_bind($lconn);
$this->info("Bind results are: ".$bind_results." which translate into boolean: ".(bool)$bind_results);
return (bool)$bind_results;
} catch (Exception $e) {
$this->error("WARNING: Exception caught during bind - ".$e->getMessage());
return false;
}
});
}
public function test_authed_bind($ldap_url, $check_cert, $start_tls, $username, $password)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
try {
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$bind_results = ldap_bind($lconn, $username, $password);
if(!$bind_results) {
$this->error("WARNING: Failed to bind to $ldap_url as $username");
return false;
} else {
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
return (bool)$lconn;
}
} catch (Exception $e) {
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
return false;
}
});
}
public function test_informational_bind($ldap_url, $check_cert, $start_tls, $username, $password,$settings)
{
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password, $settings) {
try { // TODO - copypasta'ed from test_authed_bind
$conn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
$bind_results = ldap_bind($conn, $username, $password);
if(!$bind_results) {
$this->error("WARNING: Failed to bind to $ldap_url as $username");
return false;
}
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
$result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/);
$results = ldap_get_entries($conn, $result);
$cleaned_results = $this->ldap_results_cleaner($results);
$this->line(print_r($cleaned_results,true));
//okay, great - now how do we display those results? I have no idea.
// I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it?
$this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?");
$this->debugout("Base DN is: ".$settings->ldap_basedn." and filter is: ".parenthesized_filter($settings->ldap_filter));
$search_results = ldap_search($conn, $settings->ldap_basedn, parenthesized_filter($settings->ldap_filter));
$this->info("Printing first 10 results: ");
for($i=0;$i<10;$i++) {
$this->info($search_results[$i]);
}
} catch (\Exception $e) {
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
return false;
}
});
}
/***********************************************
*
* This function executes $function - which is expected to be some kind of executable function -
* with a timeout set. It respects the timeout by forking execution and setting a strict timer
* for which to get back a SIGUSR1 or SIGUSR2 signal from the forked process.
*
***********************************************/
private function timed_boolean_execute($function)
{
if(!(function_exists('pcntl_sigtimedwait') && function_exists('posix_getpid') && function_exists('pcntl_fork') && function_exists('posix_kill') && function_exists('pcntl_wifsignaled'))) {
// POSIX functions needed for forking aren't present, just run the function inline (ignoring timeout)
$this->info('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected');
return $function();
} else {
$parent_pid = posix_getpid();
$pid = pcntl_fork();
switch($pid) {
case 0:
//we're the 'child'
if($function()) {
//SUCCESS = SIGUSR1
posix_kill($parent_pid, SIGUSR1);
} else {
//FAILURE = SIGUSR2
posix_kill($parent_pid, SIGUSR2);
}
exit();
break; //yes I know we don't need it.
case -1:
//couldn't fork
$this->error("COULD NOT FORK - assuming failure");
return false;
break; //I still know that we don't need it
default:
//we remain the 'parent', $pid is the PID of the forked process.
$siginfo = [];
$exit_status = pcntl_sigtimedwait ([SIGUSR1, SIGUSR2], $siginfo, $this->option('timeout'));
if ($exit_status == SIGUSR1) {
return true;
} else {
posix_kill($pid, SIGKILL); //make sure we don't have processes hanging around that might try and send signals during later executions, confusing us
return false;
}
break; //Yeah I get it already, shush.
}
}
}
}
+2 -12
View File
@@ -41,20 +41,10 @@ class MergeUsersByUsername extends Command
{
// Get the list of users who have an email address as their username
$users = User::where('username', 'LIKE', '%@%')->whereNull('deleted_at')->get();
$this->info($users->count().' total non-deleted users whose usernames contain a @ symbol.');
foreach ($users as $user) {
$parts = explode('@', trim($user->username));
$this->info('Checking against username '.trim($parts[0]).'.');
$bad_users = User::where('username', '=', trim($parts[0]))
->whereNull('deleted_at')
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
->get();
$parts = explode('@', $user->username);
$bad_users = User::where('username', '=', $parts[0])->whereNull('deleted_at')->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')->get();
foreach ($bad_users as $bad_user) {
$this->info($bad_user->username.' ('.$bad_user->id.') will be merged into '.$user->username.' ('.$user->id.') ');
+72 -77
View File
@@ -46,31 +46,30 @@ class MoveUploadsToNewDisk extends Command
}
$delete_local = $this->argument('delete_local');
$public_uploads['accessories'] = glob('public/uploads/accessories'."/*.*");
$public_uploads['assets'] = glob('public/uploads/assets'."/*.*");
$public_uploads['avatars'] = glob('public/uploads/avatars'."/*.*");
$public_uploads['categories'] = glob('public/uploads/categories'."/*.*");
$public_uploads['companies'] = glob('public/uploads/companies'."/*.*");
$public_uploads['components'] = glob('public/uploads/components'."/*.*");
$public_uploads['consumables'] = glob('public/uploads/consumables'."/*.*");
$public_uploads['departments'] = glob('public/uploads/departments'."/*.*");
$public_uploads['locations'] = glob('public/uploads/locations'."/*.*");
$public_uploads['manufacturers'] = glob('public/uploads/manufacturers'."/*.*");
$public_uploads['suppliers'] = glob('public/uploads/suppliers'."/*.*");
$public_uploads['assetmodels'] = glob('public/uploads/models'."/*.*");
$public_uploads['accessories'] = glob('public/accessories'.'/*.*');
$public_uploads['assets'] = glob('public/assets'.'/*.*');
$public_uploads['avatars'] = glob('public/avatars'.'/*.*');
$public_uploads['categories'] = glob('public/categories'.'/*.*');
$public_uploads['companies'] = glob('public/companies'.'/*.*');
$public_uploads['components'] = glob('public/components'.'/*.*');
$public_uploads['consumables'] = glob('public/consumables'.'/*.*');
$public_uploads['departments'] = glob('public/departments'.'/*.*');
$public_uploads['locations'] = glob('public/locations'.'/*.*');
$public_uploads['manufacturers'] = glob('public/manufacturers'.'/*.*');
$public_uploads['suppliers'] = glob('public/suppliers'.'/*.*');
$public_uploads['assetmodels'] = glob('public/models'.'/*.*');
// iterate files
foreach ($public_uploads as $public_type => $public_upload) {
$type_count = 0;
$this->info('- There are ' . count($public_upload) . ' PUBLIC ' . $public_type . ' files.');
$this->info('- There are '.count($public_upload).' PUBLIC '.$public_type.' files.');
for ($i = 0; $i < count($public_upload); $i++) {
$type_count++;
$filename = basename($public_upload[$i]);
try {
Storage::disk('public')->put('uploads/'.$public_type.'/'.$filename, file_get_contents($public_upload[$i]));
try {
Storage::disk('public')->put('uploads/'.public_type.'/'.$filename, file_get_contents($public_upload[$i]));
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
} catch (\Exception $e) {
@@ -80,87 +79,83 @@ class MoveUploadsToNewDisk extends Command
}
}
$logos = glob("public/uploads/setting*.*");
$this->info("- There are ".count($logos).' files that might be logos.');
$logos = glob('public/uploads/setting*.*');
$this->info('- There are '.count($logos).' files that might be logos.');
$type_count = 0;
foreach ($logos as $logo) {
$this->info($logo);
$type_count++;
$filename = basename($logo);
Storage::disk('public')->put('uploads/' . $filename, file_get_contents($logo));
$this->info($type_count . '. LOGO: ' . $filename . ' was copied to ' . env('PUBLIC_AWS_URL') . '/uploads/' . $filename);
Storage::disk('public')->put('uploads/'.$filename, file_get_contents($logo));
$this->info($type_count.'. LOGO: '.$filename.' was copied to '.env('PUBLIC_AWS_URL').'/uploads/'.$filename);
}
$private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*");
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*");
$private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*");
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*");
$private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*");
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*");
$private_uploads['users'] = glob('storage/private_uploads/users'."/*.*");
$private_uploads['backups'] = glob('storage/private_uploads/backups'."/*.*");
$private_uploads['assets'] = glob('storage/private_uploads/assets'.'/*.*');
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'.'/*.*');
$private_uploads['audits'] = glob('storage/private_uploads/audits'.'/*.*');
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'.'/*.*');
$private_uploads['imports'] = glob('storage/private_uploads/imports'.'/*.*');
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'.'/*.*');
$private_uploads['users'] = glob('storage/private_uploads/users'.'/*.*');
$private_uploads['backups'] = glob('storage/private_uploads/users'.'/*.*');
foreach ($private_uploads as $private_type => $private_upload) {
{
$this->info('- There are ' . count($private_upload) . ' PRIVATE ' . $private_type . ' files.');
$this->info('- There are '.count($private_upload).' PRIVATE '.$private_type.' files.');
$type_count = 0;
for ($x = 0; $x < count($private_upload); $x++) {
$type_count++;
$filename = basename($private_upload[$x]);
$type_count = 0;
for ($x = 0; $x < count($private_upload); $x++) {
$type_count++;
$filename = basename($private_upload[$x]);
try {
Storage::put($private_type . '/' . $filename, file_get_contents($private_upload[$i]));
$new_url = Storage::url($private_type . '/' . $filename, $filename);
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
try {
Storage::put($private_type.'/'.$filename, file_get_contents($private_upload[$i]));
$new_url = Storage::url($private_type.'/'.$filename, $filename);
$this->info($type_count.'. PRIVATE: '.$filename.' was copied to '.$new_url);
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
}
}
if ($delete_local == 'true') {
$public_delete_count = 0;
$private_delete_count = 0;
if ($delete_local == 'true') {
$public_delete_count = 0;
$private_delete_count = 0;
$this->info("\n\n");
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
$this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n");
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
$this->info("\n\n");
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
$this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n");
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
if ($this->confirm('Do you wish to continue?')) {
foreach ($public_uploads as $public_type => $public_upload) {
for ($i = 0; $i < count($public_upload); $i++) {
$filename = $public_upload[$i];
try {
unlink($filename);
$public_delete_count++;
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
if ($this->confirm('Do you wish to continue?')) {
foreach ($public_uploads as $public_type => $public_upload) {
for ($i = 0; $i < count($public_upload); $i++) {
$filename = $public_upload[$i];
try {
unlink($filename);
$public_delete_count++;
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
}
foreach ($private_uploads as $private_type => $private_upload) {
for ($i = 0; $i < count($private_upload); $i++) {
$filename = $private_upload[$i];
try {
unlink($filename);
$private_delete_count++;
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
}
}
$this->info($public_delete_count . ' PUBLIC local files and ' . $private_delete_count . ' PRIVATE local files were deleted from your filesystem.');
}
foreach ($private_uploads as $private_type => $private_upload) {
for ($i = 0; $i < count($private_upload); $i++) {
$filename = $private_upload[$i];
try {
unlink($filename);
$private_delete_count++;
} catch (\Exception $e) {
\Log::debug($e);
$this->error($e);
}
}
}
$this->info($public_delete_count.' PUBLIC local files and '.$private_delete_count.' PRIVATE local files were deleted from your filesystem.');
}
}
}
@@ -71,31 +71,22 @@ class ReEncodeCustomFieldNames extends Command
*/
$last_part = substr(strrchr($asset_column, '_snipeit_'), 1);
$custom_field_columns[$last_part] = $asset_column;
}
}
foreach ($fields as $field) {
$this->info($field->name.' ('.$field->id.') column should be '.$field->convertUnicodeDbSlug());
$this->info($field->name.' ('.$field->id.') column should be '.$field->convertUnicodeDbSlug().'');
/** The assets table has the column it should have, all is well */
if ($field->db_column == $field->convertUnicodeDbSlug() && \Schema::hasColumn('assets', $field->convertUnicodeDbSlug())) {
$this->info('-- ✓ This field exists on the assets table and the value for db_column matches in the custom_fields table.');
if (\Schema::hasColumn('assets', $field->convertUnicodeDbSlug())) {
$this->info('-- ✓ This field exists - all good');
/**
* There is a mismatch between the fieldname on the assets table and
* what $field->convertUnicodeDbSlug() is *now* expecting.
*/
} else {
if ($field->db_column != $field->convertUnicodeDbSlug()) {
$this->error('-- ✘ Field mismatch: '.$field->name.' value should be '.$field->convertUnicodeDbSlug().' but is '.$field->db_column.' in the custom_fields table');
} else {
$this->error('-- ✘ Field mismatch: '.$field->name.' column should be '.$field->convertUnicodeDbSlug().' but is '.$custom_field_columns[$field->id].' on the assets table.');
}
$this->warn('-- X Field mismatch: updating... ');
/** Make sure the custom_field_columns array has the ID */
if (array_key_exists($field->id, $custom_field_columns)) {
@@ -104,19 +95,13 @@ class ReEncodeCustomFieldNames extends Command
* Update the asset schema to the corrected fieldname that will be recognized by the
* system elsewhere that we use $field->convertUnicodeDbSlug()
*/
$this->info('-- ✓ Updating field from '.$field->db_column.' to '.$field->convertUnicodeDbSlug().' in the assets table');
\Schema::table('assets', function ($table) use ($custom_field_columns, $field) {
$table->renameColumn($custom_field_columns[$field->id], $field->convertUnicodeDbSlug());
});
$this->info('-- ✓ Updating field from '.$field->db_column.' to '.$field->convertUnicodeDbSlug().' in the custom fields table');
$field->db_column = $field->convertUnicodeDbSlug();
$field->save();
$this->warn('-- ✓ Field updated from '.$custom_field_columns[$field->id].' to '.$field->convertUnicodeDbSlug());
} else {
$this->warn('-- WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
$this->warn('-- X WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
}
}
+1 -8
View File
@@ -60,7 +60,7 @@ class RegenerateAssetTags extends Command
}
foreach ($total_assets as $asset) {
$start_tag++;
$output['info'][] = 'Asset tag:'.$asset->asset_tag;
$asset->asset_tag = $settings->auto_increment_prefix.$settings->auto_increment_prefix.$start_tag;
@@ -72,15 +72,8 @@ class RegenerateAssetTags extends Command
// Use forceSave here to override model level validation
$asset->forceSave();
$start_tag++;
if ($bar) {
$bar->advance();
}
}
$settings->next_auto_tag_base = Asset::zerofill($start_tag, $settings->zerofill_count);
$settings->save();
$bar->finish();
$this->info("\n");
@@ -48,7 +48,6 @@ class ResetDemoSettings extends Command
$settings->auto_increment_assets = 1;
$settings->logo = 'snipe-logo.png';
$settings->alert_email = 'service@snipe-it.io';
$settings->login_note = 'Use `admin` / `password` to login to the demo.';
$settings->header_color = null;
$settings->barcode_type = 'QRCODE';
$settings->default_currency = 'USD';
+12 -25
View File
@@ -13,8 +13,8 @@ class RestoreFromBackup extends Command
* @var string
*/
protected $signature = 'snipeit:restore
{--force : Skip the danger prompt; assuming you enter "y"}
{filename : The zip file to be migrated}
{--force : Skip the danger prompt; assuming you hit "y"}
{filename : The full path of the .zip file to be migrated}
{--no-progress : Don\'t show a progress bar}';
/**
@@ -82,7 +82,6 @@ class RestoreFromBackup extends Command
return $this->error('Could not access file: '.$filename.' - '.array_key_exists($errcode, $errors) ? $errors[$errcode] : " Unknown reason: $errcode");
}
$private_dirs = [
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
'storage/private_uploads/audits',
@@ -227,9 +226,6 @@ class RestoreFromBackup extends Command
return $this->error('Unable to invoke mysql via CLI');
}
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
// $this->info("Stderr says? ".fgets($pipes[2])); //FIXME: ditto, same.
// should we read stdout?
@@ -249,28 +245,19 @@ class RestoreFromBackup extends Command
return false;
}
$bytes_read = 0;
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
$bytes_read += strlen($buffer);
// \Log::debug("Buffer is: '$buffer'");
$bytes_written = fwrite($pipes[0], $buffer);
if ($bytes_written === false) {
$stdout = fgets($pipes[1]);
$this->info($stdout);
$stderr = fgets($pipes[2]);
$this->info($stderr);
try {
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
$bytes_read += strlen($buffer);
// \Log::debug("Buffer is: '$buffer'");
$bytes_written = fwrite($pipes[0], $buffer);
if ($bytes_written === false) {
throw new Exception("Unable to write to pipe");
}
return false;
}
} catch (\Exception $e) {
\Log::error("Error during restore!!!! ".$e->getMessage());
$err_out = fgets($pipes[1]);
$err_err = fgets($pipes[2]);
\Log::error("Error OUTPUT: ".$err_out);
$this->info($err_out);
\Log::error("Error ERROR : ".$err_err);
$this->error($err_err);
throw $e;
}
if (!feof($sql_contents) || $bytes_read == 0) {
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
}
-1
View File
@@ -24,7 +24,6 @@ class Kernel extends ConsoleKernel
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
$schedule->command('auth:clear-resets')->everyFifteenMinutes();
}
/**
+3 -5
View File
@@ -41,7 +41,7 @@ class Handler extends ExceptionHandler
public function report(Throwable $exception)
{
if ($this->shouldReport($exception)) {
\Log::error($exception);
Log::error($exception);
return parent::report($exception);
}
}
@@ -84,12 +84,10 @@ class Handler extends ExceptionHandler
switch ($e->getStatusCode()) {
case '404':
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
case '429':
return response()->json(Helper::formatStandardApiResponse('error', null, 'Too many requests'), 429);
case '405':
case '405':
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
default:
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), 405);
}
}
+13 -79
View File
@@ -1,6 +1,7 @@
<?php
namespace App\Helpers;
use App\Models\Accessory;
use App\Models\Component;
use App\Models\Consumable;
@@ -841,16 +842,6 @@ class Helper
return preg_replace('/\s+/u', '_', trim($string));
}
/**
* Return an array (or null) of the the raw and formatted date object for easy use in
* the API and the bootstrap table listings.
*
* @param $date
* @param $type
* @param $array
* @return array|string|null
*/
public static function getFormattedDateObject($date, $type = 'datetime', $array = true)
{
if ($date == '') {
@@ -858,42 +849,21 @@ class Helper
}
$settings = Setting::getSettings();
$tmp_date = new \Carbon($date);
/**
* Wrap this in a try/catch so that if Carbon crashes, for example if the $date value
* isn't actually valid, we don't crash out completely.
*
* While this *shouldn't* typically happen since we validate dates before entering them
* into the database (and we use date/datetime fields for native fields in the system),
* it is a possible scenario that a custom field could be created as an "ANY" field, data gets
* added, and then the custom field format gets edited later. If someone put bad data in the
* database before then - or if they manually edited the field's value - it will crash.
*
*/
try {
$tmp_date = new \Carbon($date);
if ($type == 'datetime') {
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
} else {
$dt['date'] = $tmp_date->format('Y-m-d');
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
}
if ($array == 'true') {
return $dt;
}
return $dt['formatted'];
} catch (\Exception $e) {
\Log::warning($e);
return $date.' (Invalid '.$type.' value.)';
if ($type == 'datetime') {
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
} else {
$dt['date'] = $tmp_date->format('Y-m-d');
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
}
if ($array == 'true') {
return $dt;
}
return $dt['formatted'];
}
// Nicked from Drupal :)
@@ -1089,40 +1059,4 @@ class Helper
return $file_name;
}
public static function formatFilesizeUnits($bytes)
{
if ($bytes >= 1073741824)
{
$bytes = number_format($bytes / 1073741824, 2) . ' GB';
}
elseif ($bytes >= 1048576)
{
$bytes = number_format($bytes / 1048576, 2) . ' MB';
}
elseif ($bytes >= 1024)
{
$bytes = number_format($bytes / 1024, 2) . ' KB';
}
elseif ($bytes > 1)
{
$bytes = $bytes . ' bytes';
}
elseif ($bytes == 1)
{
$bytes = $bytes . ' byte';
}
else
{
$bytes = '0 bytes';
}
return $bytes;
}
public static function SettingUrls(){
$settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index'];
return $settings;
}
}
@@ -9,7 +9,6 @@ use App\Models\Accessory;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Redirect;
/** This controller handles all actions related to Accessories for
@@ -80,8 +79,6 @@ class AccessoriesController extends Controller
$accessory->qty = request('qty');
$accessory->user_id = Auth::user()->id;
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
@@ -131,17 +128,6 @@ class AccessoriesController extends Controller
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$min = $accessory->numCheckedOut();
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$min"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$this->authorize($accessory);
// Update the accessory data
@@ -157,7 +143,6 @@ class AccessoriesController extends Controller
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
@@ -7,27 +7,13 @@ use App\Events\CheckoutDeclined;
use App\Events\ItemAccepted;
use App\Events\ItemDeclined;
use App\Http\Controllers\Controller;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\Contracts\Acceptable;
use App\Models\Setting;
use App\Models\User;
use App\Models\AssetModel;
use App\Models\Accessory;
use App\Models\License;
use App\Models\Component;
use App\Models\Consumable;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use App\Http\Controllers\SettingsController;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use phpDocumentor\Reflection\Types\Compound;
class AcceptanceController extends Controller
{
@@ -53,7 +39,6 @@ class AcceptanceController extends Controller
{
$acceptance = CheckoutAcceptance::find($id);
if (is_null($acceptance)) {
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
}
@@ -111,143 +96,29 @@ class AcceptanceController extends Controller
Storage::makeDirectory('private_uploads/signatures', 775);
}
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
$display_model = '';
$pdf_view_route = '';
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
$sig_filename='';
$sig_filename = '';
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-'.Str::uuid().'-'.date('Y-m-d-his').'.png';
$data_uri = e($request->input('signature_output'));
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
}
if ($request->input('asset_acceptance') == 'accepted') {
$acceptance->accept($sig_filename);
/**
* Check for the eula-pdfs directory
*/
if (! Storage::exists('private_uploads/eula-pdfs')) {
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
}
if (Setting::getSettings()->require_accept_signature == '1') {
// Check if the signature directory exists, if not create it
if (!Storage::exists('private_uploads/signatures')) {
Storage::makeDirectory('private_uploads/signatures', 775);
}
// The item was accepted, check for a signature
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
$data_uri = $request->input('signature_output');
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
// No image data is present, kick them back.
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
} else {
return redirect()->back()->with('error', trans('general.shitty_browser'));
}
}
// this is horrible
switch($acceptance->checkoutable_type){
case 'App\Models\Asset':
$pdf_view_route ='account.accept.accept-asset-eula';
$asset_model = AssetModel::find($item->model_id);
$display_model = $asset_model->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Accessory':
$pdf_view_route ='account.accept.accept-accessory-eula';
$accessory = Accessory::find($item->id);
$display_model = $accessory->name;
$assigned_to = User::find($item->assignedTo);
break;
case 'App\Models\LicenseSeat':
$pdf_view_route ='account.accept.accept-license-eula';
$license = License::find($item->license_id);
$display_model = $license->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Component':
$pdf_view_route ='account.accept.accept-component-eula';
$component = Component::find($item->id);
$display_model = $component->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Consumable':
$pdf_view_route ='account.accept.accept-consumable-eula';
$consumable = Consumable::find($item->id);
$display_model = $consumable->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
}
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
// $pdf_view_route ='account.accept.accept-asset-eula';
// $asset_model = AssetModel::find($item->model_id);
// $display_model = $asset_model->name;
// $assigned_to = User::find($item->assigned_to)->present()->fullName;
//
// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
// $pdf_view_route ='account.accept.accept-accessory-eula';
// $accessory = Accessory::find($item->id);
// $display_model = $accessory->name;
// $assigned_to = User::find($item->assignedTo);
//
// }
/**
* Gather the data for the PDF. We fire this whether there is a signature required or not,
* since we want the moment-in-time proof of what the EULA was when they accepted it.
*/
$branding_settings = SettingsController::getPDFBranding();
if (is_null($branding_settings->logo)){
$path_logo = "";
} else {
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
}
$data = [
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'eula' => $item->getEula(),
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
'logo' => $path_logo,
'date_settings' => $branding_settings->date_display_format,
];
if ($pdf_view_route!='') {
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
$pdf = Pdf::loadView($pdf_view_route, $data);
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
}
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename);
event(new CheckoutAccepted($acceptance));
$return_msg = trans('admin/users/message.accepted');
} else {
$acceptance->decline($sig_filename);
event(new CheckoutDeclined($acceptance));
$return_msg = trans('admin/users/message.declined');
}
return redirect()->to('account/accept')->with('success', $return_msg);
}
}
}
+2 -19
View File
@@ -3,34 +3,17 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use Response;
class ActionlogController extends Controller
{
public function displaySig($filename)
{
// PHP doesn't let you handle file not found errors well with
// file_get_contents, so we set the error reporting for just this class
error_reporting(0);
$this->authorize('view', \App\Models\Asset::class);
$file = config('app.private_uploads').'/signatures/'.$filename;
$filetype = Helper::checkUploadIsImage($file);
$contents = file_get_contents($file);
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
if ($contents === false) {
\Log::warn('File '.$file.' not found');
return false;
} else {
return Response::make($contents)->header('Content-Type', $filetype);
}
}
public function getStoredEula($filename){
$this->authorize('view', \App\Models\Asset::class);
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
return Response::download($file);
return Response::make($contents)->header('Content-Type', $filetype);
}
}
@@ -27,7 +27,8 @@ class AccessoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Accessory::class);
$allowed_columns = ['id', 'name', 'model_number', 'eol', 'notes', 'created_at', 'min_amt', 'company_id'];
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
$allowed_columns =
@@ -39,8 +40,7 @@ class AccessoriesController extends Controller
'notes',
'created_at',
'min_amt',
'company_id',
'notes',
'company_id'
];
@@ -70,10 +70,6 @@ class AccessoriesController extends Controller
$accessories->where('location_id','=',$request->input('location_id'));
}
if ($request->filled('notes')) {
$accessories->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($accessories) && ($request->get('offset') > $accessories->count())) ? $accessories->count() : $request->get('offset', 0);
@@ -35,8 +35,7 @@ class AssetMaintenancesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Asset::class);
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
$maintenances = AssetMaintenance::with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin');
if ($request->filled('search')) {
$maintenances = $maintenances->TextSearch($request->input('search'));
@@ -46,15 +45,6 @@ class AssetMaintenancesController extends Controller
$maintenances->where('asset_id', '=', $request->input('asset_id'));
}
if ($request->filled('supplier_id')) {
$maintenances->where('supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('asset_maintenance_type')) {
$maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($maintenances) && ($request->get('offset') > $maintenances->count())) ? $maintenances->count() : $request->get('offset', 0);
@@ -74,7 +64,6 @@ class AssetMaintenancesController extends Controller
'asset_tag',
'asset_name',
'user_id',
'supplier'
];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
@@ -83,9 +72,6 @@ class AssetMaintenancesController extends Controller
case 'user_id':
$maintenances = $maintenances->OrderAdmin($order);
break;
case 'supplier':
$maintenances = $maintenances->OrderBySupplier($order);
break;
case 'asset_tag':
$maintenances = $maintenances->OrderByTag($order);
break;
@@ -116,7 +102,7 @@ class AssetMaintenancesController extends Controller
*/
public function store(Request $request)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// create a new model instance
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
@@ -168,7 +154,7 @@ class AssetMaintenancesController extends Controller
*/
public function update(Request $request, $assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
@@ -232,7 +218,7 @@ class AssetMaintenancesController extends Controller
*/
public function destroy($assetMaintenanceId)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// Check if the asset maintenance exists
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
@@ -70,10 +70,6 @@ class AssetModelsController extends Controller
$assetmodels->onlyTrashed();
}
if ($request->filled('category_id')) {
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
}
if ($request->filled('search')) {
$assetmodels->TextSearch($request->input('search'));
}
+21 -49
View File
@@ -52,7 +52,7 @@ class AssetsController extends Controller
*/
public function index(Request $request, $audit = null)
{
\Log::debug(Route::currentRouteName());
$filter_non_deprecable_assets = false;
/**
@@ -345,7 +345,6 @@ class AssetsController extends Controller
}
/**
* Here we're just determining which Transformer (via $transformer) to use based on the
* variables we set earlier on in this method - we default to AssetsTransformer.
@@ -522,7 +521,7 @@ class AssetsController extends Controller
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost')); // this is the API's store method, so I don't know that I want to do this? Confusing. FIXME (or not?!)
$asset->purchase_date = $request->get('purchase_date', null);
$asset->assigned_to = $request->get('assigned_to', null);
$asset->supplier_id = $request->get('supplier_id');
$asset->supplier_id = $request->get('supplier_id', 0);
$asset->requestable = $request->get('requestable', 0);
$asset->rtd_location_id = $request->get('rtd_location_id', null);
$asset->location_id = $request->get('rtd_location_id', null);
@@ -544,11 +543,11 @@ class AssetsController extends Controller
foreach ($model->fieldset->fields as $field) {
// Set the field value based on what was sent in the request
$field_val = $request->input($field->db_column, null);
$field_val = $request->input($field->convertUnicodeDbSlug(), null);
// If input value is null, use custom field's default value
if ($field_val == null) {
\Log::debug('Field value for '.$field->db_column.' is null');
\Log::debug('Field value for '.$field->convertUnicodeDbSlug().' is null');
$field_val = $field->defaultValue($request->get('model_id'));
\Log::debug('Use the default fieldset value of '.$field->defaultValue($request->get('model_id')));
}
@@ -563,13 +562,13 @@ class AssetsController extends Controller
if (($field_val == null) && ($request->has('model_id') != '')) {
$field_val = \Crypt::encrypt($field->defaultValue($request->get('model_id')));
} else {
$field_val = \Crypt::encrypt($request->input($field->db_column));
$field_val = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
}
}
$asset->{$field->db_column} = $field_val;
$asset->{$field->convertUnicodeDbSlug()} = $field_val;
}
}
@@ -634,13 +633,13 @@ class AssetsController extends Controller
// Update custom fields
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
foreach ($model->fieldset->fields as $field) {
if ($request->has($field->db_column)) {
if ($request->has($field->convertUnicodeDbSlug())) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
@@ -714,53 +713,29 @@ class AssetsController extends Controller
* @since [v5.1.18]
* @return JsonResponse
*/
public function restore(Request $request, $assetId = null)
public function restore($assetId = null)
{
// Get asset information
$asset = Asset::withTrashed()->find($assetId);
$this->authorize('delete', $asset);
if (isset($asset->id)) {
// Restore the asset
Asset::withTrashed()->where('id', $assetId)->restore();
if ($asset->deleted_at=='') {
$message = 'Asset was not deleted. No data was changed.';
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->user_id = Auth::user()->id;
$logaction->logaction('restored');
} else {
$message = trans('admin/hardware/message.restore.success');
// Restore the asset
Asset::withTrashed()->where('id', $assetId)->restore();
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->user_id = Auth::user()->id;
$logaction->logaction('restored');
}
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset, $request), $message));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.restore.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
* Checkout an asset by its tag.
*
* @author [N. Butler]
* @param string $tag
* @since [v6.0.5]
* @return JsonResponse
*/
public function checkoutByTag(AssetCheckoutRequest $request, $tag)
{
if ($asset = Asset::where('asset_tag', $tag)->first()) {
return $this->checkout($request, $asset->id);
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
}
/**
* Checkout an asset
@@ -811,9 +786,6 @@ class AssetsController extends Controller
$error_payload['target_type'] = 'user';
}
if ($request->filled('status_id')) {
$asset->status_id = $request->get('status_id');
}
if (! isset($target)) {
@@ -872,7 +844,7 @@ class AssetsController extends Controller
$asset->assignedTo()->disassociate($asset);
$asset->accepted = null;
if ($request->has('name')) {
if ($request->filled('name')) {
$asset->name = $request->input('name');
}
@@ -32,28 +32,6 @@ class CategoriesController extends Controller
$categories = $categories->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$categories->where('name', '=', $request->input('name'));
}
if ($request->filled('category_type')) {
$categories->where('category_type', '=', $request->input('category_type'));
}
if ($request->filled('use_default_eula')) {
$categories->where('use_default_eula', '=', $request->input('use_default_eula'));
}
if ($request->filled('require_acceptance')) {
$categories->where('require_acceptance', '=', $request->input('require_acceptance'));
}
if ($request->filled('checkin_email')) {
$categories->where('checkin_email', '=', $request->input('checkin_email'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($categories) && ($request->get('offset') > $categories->count())) ? $categories->count() : $request->get('offset', 0);
@@ -43,11 +43,6 @@ class CompaniesController extends Controller
$companies->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$companies->where('name', '=', $request->input('name'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($companies) && ($request->get('offset') > $companies->count())) ? $companies->count() : $request->get('offset', 0);
@@ -40,7 +40,6 @@ class ComponentsController extends Controller
'purchase_cost',
'qty',
'image',
'notes',
];
@@ -51,10 +50,6 @@ class ComponentsController extends Controller
$components = $components->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$components->where('name', '=', $request->input('name'));
}
if ($request->filled('company_id')) {
$components->where('company_id', '=', $request->input('company_id'));
}
@@ -67,10 +62,6 @@ class ComponentsController extends Controller
$components->where('location_id', '=', $request->input('location_id'));
}
if ($request->filled('notes')) {
$components->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($components) && ($request->get('offset') > $components->count())) ? $components->count() : $request->get('offset', 0);
@@ -42,7 +42,6 @@ class ConsumablesController extends Controller
'item_no',
'qty',
'image',
'notes',
];
@@ -55,10 +54,6 @@ class ConsumablesController extends Controller
$consumables = $consumables->TextSearch(e($request->input('search')));
}
if ($request->filled('name')) {
$consumables->where('name', '=', $request->input('name'));
}
if ($request->filled('company_id')) {
$consumables->where('company_id', '=', $request->input('company_id'));
}
@@ -79,10 +74,6 @@ class ConsumablesController extends Controller
$consumables->where('location_id','=',$request->input('location_id'));
}
if ($request->filled('notes')) {
$consumables->where('notes','=',$request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
@@ -42,22 +42,6 @@ class DepartmentsController extends Controller
$departments = $departments->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$departments->where('name', '=', $request->input('name'));
}
if ($request->filled('company_id')) {
$departments->where('company_id', '=', $request->input('company_id'));
}
if ($request->filled('manager_id')) {
$departments->where('manager_id', '=', $request->input('manager_id'));
}
if ($request->filled('location_id')) {
$departments->where('location_id', '=', $request->input('location_id'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($departments) && ($request->get('offset') > $departments->count())) ? $departments->count() : $request->get('offset', 0);
@@ -28,10 +28,6 @@ class GroupsController extends Controller
$groups = $groups->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$groups->where('name', '=', $request->input('name'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($groups) && ($request->get('offset') > $groups->count())) ? $groups->count() : $request->get('offset', 0);
@@ -134,14 +134,7 @@ class ImportController extends Controller
\Log::debug('NO BACKUP requested via importer');
}
$import = Import::find($import_id);
if(is_null($import)){
$error[0][0] = trans("validation.exists", ["attribute" => "file"]);
return response()->json(Helper::formatStandardApiResponse('import-errors', null, $error), 500);
}
$errors = $request->import($import);
$errors = $request->import(Import::find($import_id));
$redirectTo = 'hardware.index';
switch ($request->get('import-type')) {
case 'asset':
@@ -116,20 +116,16 @@ class LicenseSeatsController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
// the logging functions expect only one "target". if both asset and user are present in the request,
// we simply let assets take precedence over users...
if ($licenseSeat->isDirty('assigned_to')) {
$target = $is_checkin ? $oldUser : User::find($licenseSeat->assigned_to);
}
if ($licenseSeat->isDirty('asset_id')) {
$target = $is_checkin ? $oldAsset : Asset::find($licenseSeat->asset_id);
}
if (is_null($target)){
return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
}
if ($licenseSeat->save()) {
// 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...
$changes = $licenseSeat->getChanges();
if (array_key_exists('assigned_to', $changes)) {
$target = $is_checkin ? $oldUser : User::find($changes['assigned_to']);
}
if (array_key_exists('asset_id', $changes)) {
$target = $is_checkin ? $oldAsset : Asset::find($changes['asset_id']);
}
if ($is_checkin) {
$licenseSeat->logCheckin($target, $request->input('note'));
@@ -26,8 +26,7 @@ class LicensesController extends Controller
public function index(Request $request)
{
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count'));
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier', 'category')->withCount('freeSeats as free_seats_count'));
if ($request->filled('company_id')) {
$licenses->where('company_id', '=', $request->input('company_id'));
@@ -73,6 +72,9 @@ class LicensesController extends Controller
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
}
if ($request->filled('supplier_id')) {
$licenses->where('supplier_id', '=', $request->input('supplier_id'));
}
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
$licenses->where('maintained','=',1);
@@ -146,10 +148,9 @@ class LicensesController extends Controller
}
$total = $licenses->count();
$licenses = $licenses->skip($offset)->take($limit)->get();
return (new LicensesTransformer)->transformLicenses($licenses, $total);
return (new LicensesTransformer)->transformLicenses($licenses, $total);
}
/**
@@ -53,30 +53,6 @@ class LocationsController extends Controller
$locations = $locations->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$locations->where('locations.name', '=', $request->input('name'));
}
if ($request->filled('address')) {
$locations->where('locations.address', '=', $request->input('address'));
}
if ($request->filled('address2')) {
$locations->where('locations.address2', '=', $request->input('address2'));
}
if ($request->filled('city')) {
$locations->where('locations.city', '=', $request->input('city'));
}
if ($request->filled('zip')) {
$locations->where('locations.zip', '=', $request->input('zip'));
}
if ($request->filled('country')) {
$locations->where('locations.country', '=', $request->input('country'));
}
$offset = (($locations) && (request('offset') > $locations->count())) ? $locations->count() : request('offset', 0);
// Check to make sure the limit is not higher than the max allowed
@@ -37,26 +37,6 @@ class ManufacturersController extends Controller
$manufacturers = $manufacturers->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$manufacturers->where('name', '=', $request->input('name'));
}
if ($request->filled('url')) {
$manufacturers->where('url', '=', $request->input('url'));
}
if ($request->filled('support_url')) {
$manufacturers->where('support_url', '=', $request->input('support_url'));
}
if ($request->filled('support_phone')) {
$manufacturers->where('support_phone', '=', $request->input('support_phone'));
}
if ($request->filled('support_email')) {
$manufacturers->where('support_email', '=', $request->input('support_email'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($manufacturers) && ($request->get('offset') > $manufacturers->count())) ? $manufacturers->count() : $request->get('offset', 0);
+6 -119
View File
@@ -5,37 +5,10 @@ namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\CheckoutRequest;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Laravel\Passport\TokenRepository;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Gate;
use DB;
use Auth;
class ProfileController extends Controller
{
/**
* The token repository implementation.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
/**
* Create a controller instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Illuminate\Contracts\Validation\Factory $validation
* @return void
*/
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
{
$this->validation = $validation;
$this->tokenRepository = $tokenRepository;
}
/**
* Display a listing of requested assets.
*
@@ -56,11 +29,11 @@ class ProfileController extends Controller
// Make sure the asset and request still exist
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
$results['rows'][] = [
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
'name' => e($checkoutRequest->itemRequested()->present()->name()),
'type' => e($checkoutRequest->itemType()),
'qty' => (int) $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
'image' => $checkoutRequest->itemRequested()->present()->getImageUrl(),
'name' => $checkoutRequest->itemRequested()->present()->name(),
'type' => $checkoutRequest->itemType(),
'qty' => $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? $checkoutRequest->location()->name : null,
'expected_checkin' => Helper::getFormattedDateObject($checkoutRequest->itemRequested()->expected_checkin, 'datetime'),
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
];
@@ -69,90 +42,4 @@ class ProfileController extends Controller
return $results;
}
/**
* Delete an API token
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0.5]
*
* @return \Illuminate\Http\Response
*/
public function createApiToken(Request $request) {
if (!Gate::allows('self.api')) {
abort(403);
}
$accessTokenName = $request->input('name', 'Auth Token');
if ($accessToken = Auth::user()->createToken($accessTokenName)->accessToken) {
// Get the ID so we can return that with the payload
$token = DB::table('oauth_access_tokens')->where('user_id', '=', Auth::user()->id)->where('name','=',$accessTokenName)->orderBy('created_at', 'desc')->first();
$accessTokenData['id'] = $token->id;
$accessTokenData['token'] = $accessToken;
$accessTokenData['name'] = $accessTokenName;
return response()->json(Helper::formatStandardApiResponse('success', $accessTokenData, 'Personal access token '.$accessTokenName.' created successfully'));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'Token could not be created.'));
}
/**
* Delete an API token
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0.5]
*
* @return \Illuminate\Http\Response
*/
public function deleteApiToken($tokenId) {
if (!Gate::allows('self.api')) {
abort(403);
}
$token = $this->tokenRepository->findForUser(
$tokenId, Auth::user()->getAuthIdentifier()
);
if (is_null($token)) {
return new Response('', 404);
}
$token->revoke();
return new Response('', Response::HTTP_NO_CONTENT);
}
/**
* Show user's API tokens
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0.5]
*
* @return \Illuminate\Http\Response
*/
public function showApiTokens(Request $request) {
if (!Gate::allows('self.api')) {
abort(403);
}
$tokens = $this->tokenRepository->forUser(Auth::user()->getAuthIdentifier());
$token_values = $tokens->load('client')->filter(function ($token) {
return $token->client->personal_access_client && ! $token->revoked;
})->values();
return response()->json(Helper::formatStandardApiResponse('success', $token_values, null));
}
}
@@ -2,9 +2,6 @@
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Helpers\StorageHelper;
use App\Http\Transformers\DatatablesTransformer;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Ldap;
@@ -21,7 +18,6 @@ use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\SlackSettingsRequest;
use App\Http\Transformers\LoginAttemptsTransformer;
class SettingsController extends Controller
@@ -268,52 +264,4 @@ class SettingsController extends Controller
return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total);
}
public function listBackups() {
$settings = Setting::getSettings();
$path = 'app/backups';
$backup_files = Storage::files($path);
$files_raw = [];
$count = 0;
if (count($backup_files) > 0) {
for ($f = 0; $f < count($backup_files); $f++) {
// Skip dotfiles like .gitignore and .DS_STORE
if ((substr(basename($backup_files[$f]), 0, 1) != '.')) {
$file_timestamp = Storage::lastModified($backup_files[$f]);
$files_raw[] = [
'filename' => basename($backup_files[$f]),
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
'modified_value' => $file_timestamp,
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
];
$count++;
}
}
}
$files = array_reverse($files_raw);
return (new DatatablesTransformer)->transformDatatables($files, $count);
}
public function downloadBackup($file) {
$path = 'app/backups';
if (Storage::exists($path.'/'.$file)) {
$headers = ['ContentType' => 'application/zip'];
return Storage::download($path.'/'.$file, $file, $headers);
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found'));
}
}
}
@@ -30,24 +30,6 @@ class StatuslabelsController extends Controller
$statuslabels = $statuslabels->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$statuslabels->where('name', '=', $request->input('name'));
}
// if a status_type is passed, filter by that
if ($request->filled('status_type')) {
if (strtolower($request->input('status_type')) == 'pending') {
$statuslabels = $statuslabels->Pending();
} elseif (strtolower($request->input('status_type')) == 'archived') {
$statuslabels = $statuslabels->Archived();
} elseif (strtolower($request->input('status_type')) == 'deployable') {
$statuslabels = $statuslabels->Deployable();
} elseif (strtolower($request->input('status_type')) == 'undeployable') {
$statuslabels = $statuslabels->Undeployable();
}
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($statuslabels) && ($request->get('offset') > $statuslabels->count())) ? $statuslabels->count() : $request->get('offset', 0);
@@ -98,8 +80,8 @@ class StatuslabelsController extends Controller
if ($statuslabel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
}
/**
@@ -118,7 +100,6 @@ class StatuslabelsController extends Controller
return (new StatuslabelsTransformer)->transformStatuslabel($statuslabel);
}
/**
* Update the specified resource in storage.
*
@@ -135,7 +116,6 @@ class StatuslabelsController extends Controller
$request->except('deployable', 'pending', 'archived');
if (! $request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
}
@@ -181,8 +161,6 @@ class StatuslabelsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/statuslabels/message.assoc_assets')));
}
/**
* Show a count of assets by status label for pie chart
*
@@ -34,46 +34,6 @@ class SuppliersController extends Controller
$suppliers = $suppliers->TextSearch($request->input('search'));
}
if ($request->filled('name')) {
$suppliers->where('name', '=', $request->input('name'));
}
if ($request->filled('address')) {
$suppliers->where('address', '=', $request->input('address'));
}
if ($request->filled('address2')) {
$suppliers->where('address2', '=', $request->input('address2'));
}
if ($request->filled('city')) {
$suppliers->where('city', '=', $request->input('city'));
}
if ($request->filled('zip')) {
$suppliers->where('zip', '=', $request->input('zip'));
}
if ($request->filled('country')) {
$suppliers->where('country', '=', $request->input('country'));
}
if ($request->filled('fax')) {
$suppliers->where('fax', '=', $request->input('fax'));
}
if ($request->filled('email')) {
$suppliers->where('email', '=', $request->input('email'));
}
if ($request->filled('url')) {
$suppliers->where('url', '=', $request->input('url'));
}
if ($request->filled('notes')) {
$suppliers->where('notes', '=', $request->input('notes'));
}
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
$offset = (($suppliers) && ($request->get('offset') > $suppliers->count())) ? $suppliers->count() : $request->get('offset', 0);
+5 -61
View File
@@ -7,7 +7,6 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserRequest;
use App\Http\Transformers\AccessoriesTransformer;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\ConsumablesTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Http\Transformers\UsersTransformer;
@@ -36,7 +35,6 @@ class UsersController extends Controller
$users = User::select([
'users.activated',
'users.created_by',
'users.address',
'users.avatar',
'users.city',
@@ -64,10 +62,9 @@ class UsersController extends Controller
'users.updated_at',
'users.username',
'users.zip',
'users.remote',
'users.ldap_import',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables')
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
$users = Company::scopeCompanyables($users);
@@ -90,10 +87,6 @@ class UsersController extends Controller
$users = $users->where('users.location_id', '=', $request->input('location_id'));
}
if ($request->filled('created_by')) {
$users = $users->where('users.created_by', '=', $request->input('created_by'));
}
if ($request->filled('email')) {
$users = $users->where('users.email', '=', $request->input('email'));
}
@@ -138,30 +131,6 @@ class UsersController extends Controller
$users = $users->where('users.manager_id','=',$request->input('manager_id'));
}
if ($request->filled('ldap_import')) {
$users = $users->where('ldap_import', '=', $request->input('ldap_import'));
}
if ($request->filled('remote')) {
$users = $users->where('remote', '=', $request->input('remote'));
}
if ($request->filled('assets_count')) {
$users->has('assets', '=', $request->input('assets_count'));
}
if ($request->filled('consumables_count')) {
$users->has('consumables', '=', $request->input('consumables_count'));
}
if ($request->filled('licenses_count')) {
$users->has('licenses', '=', $request->input('licenses_count'));
}
if ($request->filled('accessories_count')) {
$users->has('accessories', '=', $request->input('accessories_count'));
}
if ($request->filled('search')) {
$users = $users->TextSearch($request->input('search'));
}
@@ -187,9 +156,6 @@ class UsersController extends Controller
case 'department':
$users = $users->OrderDepartment($order);
break;
case 'created_by':
$users = $users->OrderByCreatedBy($order);
break;
case 'company':
$users = $users->OrderCompany($order);
break;
@@ -200,7 +166,7 @@ class UsersController extends Controller
'assets', 'accessories', 'consumables', 'licenses', 'groups', 'activated', 'created_at',
'two_factor_enrolled', 'two_factor_optin', 'last_login', 'assets_count', 'licenses_count',
'consumables_count', 'accessories_count', 'phone', 'address', 'city', 'state',
'country', 'zip', 'id', 'ldap_import', 'remote',
'country', 'zip', 'id', 'ldap_import',
];
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
@@ -479,24 +445,6 @@ class UsersController extends Controller
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
}
/**
* Return JSON containing a list of consumables assigned to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $userId
* @return string JSON
*/
public function consumables(Request $request, $id)
{
$this->authorize('view', User::class);
$this->authorize('view', Consumable::class);
$user = User::findOrFail($id);
$consumables = $user->consumables;
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
}
/**
* Return JSON containing a list of accessories assigned to a user.
*
@@ -527,14 +475,10 @@ class UsersController extends Controller
{
$this->authorize('view', User::class);
$this->authorize('view', License::class);
if ($user = User::where('id', $id)->withTrashed()->first()) {
$licenses = $user->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
$user = User::where('id', $id)->withTrashed()->first();
$licenses = $user->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
}
/**
@@ -65,7 +65,7 @@ class AssetMaintenancesController extends Controller
*/
public function create()
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
$asset = null;
if ($asset = Asset::find(request('asset_id'))) {
@@ -96,7 +96,7 @@ class AssetMaintenancesController extends Controller
*/
public function store(Request $request)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// create a new model instance
$assetMaintenance = new AssetMaintenance();
$assetMaintenance->supplier_id = $request->input('supplier_id');
@@ -148,7 +148,7 @@ class AssetMaintenancesController extends Controller
*/
public function edit($assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the improvement management page
@@ -199,7 +199,7 @@ class AssetMaintenancesController extends Controller
*/
public function update(Request $request, $assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
@@ -267,7 +267,7 @@ class AssetMaintenancesController extends Controller
*/
public function destroy($assetMaintenanceId)
{
$this->authorize('update', Asset::class);
$this->authorize('edit', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
+2 -23
View File
@@ -8,7 +8,6 @@ use App\Models\AssetModel;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Validator;
use Redirect;
use Request;
use Storage;
@@ -91,9 +90,7 @@ class AssetModelsController extends Controller
// Was it created?
if ($model->save()) {
if ($this->shouldAddDefaultValues($request->input())) {
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
}
$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'));
}
// Redirect to the new model page
@@ -166,9 +163,7 @@ class AssetModelsController extends Controller
$model->fieldset_id = $request->input('custom_fieldset');
if ($this->shouldAddDefaultValues($request->input())) {
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
}
$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'));
}
}
@@ -456,21 +451,6 @@ class AssetModelsController extends Controller
*/
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues)
{
$data = array();
foreach ($defaultValues as $customFieldId => $defaultValue) {
$customField = \App\Models\CustomField::find($customFieldId);
$data[$customField->db_column] = $defaultValue;
}
$rules = $model->fieldset->validation_rules();
$validator = Validator::make($data, $rules);
if($validator->fails()){
return false;
}
foreach ($defaultValues as $customFieldId => $defaultValue) {
if(is_array($defaultValue)){
$model->defaultValues()->attach($customFieldId, ['default_value' => implode(', ', $defaultValue)]);
@@ -478,7 +458,6 @@ class AssetModelsController extends Controller
$model->defaultValues()->attach($customFieldId, ['default_value' => $defaultValue]);
}
}
return true;
}
/**
@@ -1,155 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\StorageHelper;
use App\Http\Requests\AssetFileRequest;
use App\Models\Actionlog;
use App\Models\AssetModel;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use enshrined\svgSanitize\Sanitizer;
class AssetModelsFilesController extends Controller
{
/**
* Upload a file to the server.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param AssetFileRequest $request
* @param int $modelId
* @return Redirect
* @since [v1.0]
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function store(AssetFileRequest $request, $modelId = null)
{
if (! $model = AssetModel::find($modelId)) {
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('update', $model);
if ($request->hasFile('file')) {
if (! Storage::exists('private_uploads/assetmodels')) {
Storage::makeDirectory('private_uploads/assetmodels', 775);
}
foreach ($request->file('file') as $file) {
$extension = $file->getClientOriginalExtension();
$file_name = 'model-'.$model->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
// Check for SVG and sanitize it
if ($extension=='svg') {
\Log::debug('This is an SVG');
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($file->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
try {
Storage::put('private_uploads/assetmodels/'.$file_name, $cleanSVG);
} catch (\Exception $e) {
\Log::debug('Upload no workie :( ');
\Log::debug($e);
}
} else {
Storage::put('private_uploads/assetmodels/'.$file_name, file_get_contents($file));
}
$model->logUpload($file_name, e($request->get('notes')));
}
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
}
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
}
/**
* Check for permissions and display the file.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $modelId
* @param int $fileId
* @since [v1.0]
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($modelId = null, $fileId = null, $download = true)
{
$model = AssetModel::find($modelId);
// the asset is valid
if (isset($model->id)) {
$this->authorize('view', $model);
if (! $log = Actionlog::find($fileId)) {
return response('No matching record for that model/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/assetmodels/'.$log->filename;
\Log::debug('Checking for '.$file);
if (! Storage::exists($file)) {
return response('File '.$file.' not found on server', 404)
->header('Content-Type', 'text/plain');
}
if ($download != 'true') {
if ($contents = file_get_contents(Storage::url($file))) {
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
}
return JsonResponse::create(['error' => 'Failed validation: '], 500);
}
return StorageHelper::downloader($file);
}
// Prepare the error message
$error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]);
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', $error);
}
/**
* Delete the associated file
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $modelId
* @param int $fileId
* @since [v1.0]
* @return View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy($modelId = null, $fileId = null)
{
$model = AssetModel::find($modelId);
$this->authorize('update', $model);
$rel_path = 'private_uploads/assetmodels';
// the asset is valid
if (isset($model->id)) {
$this->authorize('update', $model);
$log = Actionlog::find($fileId);
if ($log) {
if (Storage::exists($rel_path.'/'.$log->filename)) {
Storage::delete($rel_path.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
}
return redirect()->back()
->with('success', trans('admin/hardware/message.deletefile.success'));
}
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
}
@@ -98,22 +98,17 @@ class AssetCheckinController extends Controller
}
$asset->location_id = $asset->rtd_location_id;
\Log::debug('After Location ID: '.$asset->location_id);
\Log::debug('After RTD Location ID: '.$asset->rtd_location_id);
if ($request->filled('location_id')) {
\Log::debug('NEW Location ID: '.$request->get('location_id'));
$asset->location_id = e($request->get('location_id'));
}
$checkin_at = date('Y-m-d H:i:s');
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
$checkin_at = $request->get('checkin_at');
}
if(!empty($asset->licenseseats->all())){
foreach ($asset->licenseseats as $seat){
$seat->assigned_to = null;
$seat->save();
}
$checkin_at = date('Y-m-d');
if ($request->filled('checkin_at')) {
$checkin_at = $request->input('checkin_at');
}
// Get all pending Acceptances for this asset and delete them
@@ -80,15 +80,6 @@ class AssetCheckoutController extends Controller
$asset->status_id = $request->get('status_id');
}
if(!empty($asset->licenseseats->all())){
if(request('checkout_to_type') == 'user') {
foreach ($asset->licenseseats as $seat){
$seat->assigned_to = $target->id;
$seat->save();
}
}
}
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $request->get('name'))) {
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
}
@@ -20,7 +20,6 @@ use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Cookie;
use Input;
use Intervention\Image\Facades\Image;
use League\Csv\Reader;
@@ -138,12 +137,12 @@ class AssetsController extends Controller
$asset->archived = '0';
$asset->physical = '1';
$asset->depreciate = '0';
$asset->status_id = request('status_id');
$asset->status_id = request('status_id', 0);
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
$asset->purchase_date = request('purchase_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null);
$asset->supplier_id = request('supplier_id', 0);
$asset->requestable = request('requestable', 0);
$asset->rtd_location_id = request('rtd_location_id', null);
@@ -168,17 +167,17 @@ class AssetsController extends Controller
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
} else {
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
@@ -202,30 +201,18 @@ class AssetsController extends Controller
}
$success = true;
}
}
if ($success) {
// Redirect to the asset listing page
$minutes = 518400;
// dd( $_POST['options']);
// Cookie::queue(Cookie::make('optional_info', json_decode($_POST['options']), $minutes));
return redirect()->route('hardware.index')
->with('success', trans('admin/hardware/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($asset->getErrors());
}
public function getOptionCookie(Request $request){
$value = $request->cookie('optional_info');
echo $value;
return $value;
}
/**
* Returns a view that presents a form to edit an existing asset.
*
@@ -248,7 +235,6 @@ class AssetsController extends Controller
->with('statuslabel_types', Helper::statusTypeList());
}
/**
* Returns a view that presents information about an asset for detail view.
*
@@ -323,7 +309,6 @@ class AssetsController extends Controller
$asset->location_id = $request->input('rtd_location_id', null);
}
if ($request->filled('image_delete')) {
try {
unlink(public_path().'/uploads/assets/'.$asset->image);
@@ -356,17 +341,17 @@ class AssetsController extends Controller
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
} else {
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
$asset->{$field->convertUnicodeDbSlug()} = implode(', ', $request->input($field->convertUnicodeDbSlug()));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
@@ -416,24 +401,6 @@ class AssetsController extends Controller
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
}
/**
* Searches the assets table by serial, and redirects if it finds one
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function getAssetBySerial(Request $request)
{
$topsearch = ($request->get('topsearch')=="true");
if (!$asset = Asset::where('serial', '=', $request->get('serial'))->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('view', $asset);
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
}
/**
* Searches the assets table by asset tag, and redirects if it finds one
*
@@ -453,7 +420,6 @@ class AssetsController extends Controller
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
}
/**
* Return a QR code for the asset
*
@@ -826,7 +792,6 @@ class AssetsController extends Controller
return view('hardware/audit-overdue');
}
public function auditStore(Request $request, $id)
{
$this->authorize('audit', Asset::class);
@@ -857,7 +822,6 @@ class AssetsController extends Controller
$asset->location_id = $request->input('location_id');
}
if ($asset->save()) {
$file_name = '';
// Upload an image, if attached
@@ -874,13 +838,12 @@ class AssetsController extends Controller
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.audit.success'));
}
}
public function getRequestedIndex($user_id = null)
{
$this->authorize('index', Asset::class);
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->whereNull('canceled_at')->with('user', 'requestedItem');
if ($user_id) {
@@ -2,16 +2,21 @@
namespace App\Http\Controllers\Assets;
use App\Events\CheckoutableCheckedIn;
use App\Models\Actionlog;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
use App\Models\CheckoutAcceptance;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use App\Http\Requests\AssetCheckinRequest;
use Illuminate\Database\Eloquent\Builder;
class BulkAssetsController extends Controller
{
@@ -31,13 +36,9 @@ class BulkAssetsController extends Controller
$this->authorize('update', Asset::class);
if (! $request->filled('ids')) {
return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected'));
return redirect()->back()->with('error', 'No assets selected');
}
// Figure out where we need to send the user after the update is complete, and store that in the session
$bulk_back_url = request()->headers->get('referer');
session(['bulk_back_url' => $bulk_back_url]);
$asset_ids = array_values(array_unique($request->input('ids')));
@@ -54,8 +55,14 @@ class BulkAssetsController extends Controller
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
return view('hardware/bulk-delete')->with('assets', $assets);
case 'checkin':
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
$assets->each(function ($asset) {
$this->authorize('checkin', $asset);
});
return view('hardware/bulk-checkin')->with('assets', $assets);
case 'edit':
return view('hardware/bulk')
->with('assets', $asset_ids)
@@ -78,15 +85,10 @@ class BulkAssetsController extends Controller
{
$this->authorize('update', Asset::class);
// Get the back url from the session and then destroy the session
$bulk_back_url = route('hardware.index');
if ($request->session()->has('bulk_back_url')) {
$bulk_back_url = $request->session()->pull('bulk_back_url');
}
\Log::debug($request->input('ids'));
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()->route('hardware.index')->with('warning', trans('No assets selected, so nothing was updated.'));
}
$assets = array_keys($request->input('ids'));
@@ -157,13 +159,11 @@ class BulkAssetsController extends Controller
->update($this->update_array);
} // endforeach
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.update.success'));
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.update.success'));
// no values given, nothing to update
}
// no values given, nothing to update
return redirect($bulk_back_url)->with('warning', trans('admin/hardware/message.update.nothing_updated'));
return redirect()->route('hardware.index')->with('warning', trans('admin/hardware/message.update.nothing_updated'));
}
/**
@@ -200,11 +200,6 @@ class BulkAssetsController extends Controller
{
$this->authorize('delete', Asset::class);
$bulk_back_url = route('hardware.index');
if ($request->session()->has('bulk_back_url')) {
$bulk_back_url = $request->session()->pull('bulk_back_url');
}
if ($request->filled('ids')) {
$assets = Asset::find($request->get('ids'));
foreach ($assets as $asset) {
@@ -216,13 +211,15 @@ class BulkAssetsController extends Controller
->update($update_array);
} // endforeach
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.delete.success'));
// no values given, nothing to update
}
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.delete.nothing_updated'));
return redirect()->to('hardware')->with('info', trans('admin/hardware/message.delete.nothing_updated'));
}
/**
* Show Bulk Checkout Page
* @return View View to checkout multiple assets
@@ -230,8 +227,6 @@ class BulkAssetsController extends Controller
public function showCheckout()
{
$this->authorize('checkout', Asset::class);
// Filter out assets that are not deployable.
return view('hardware/bulk-checkout');
}
@@ -241,9 +236,6 @@ class BulkAssetsController extends Controller
*/
public function storeCheckout(Request $request)
{
$this->authorize('checkout', Asset::class);
try {
$admin = Auth::user();
@@ -302,4 +294,55 @@ class BulkAssetsController extends Controller
return redirect()->to('hardware/bulk-checkout')->with('error', $e->getErrors());
}
}
/**
* Show Bulk Checkout Page
* @return View View to checkout multiple assets
*/
public function showCheckin(Request $request)
{
$this->authorize('checkin', Asset::class);
$assets = Asset::find($request->input('ids'));
return view('hardware/bulk-checkin')->with($assets);
}
/**
* Process Multiple Checkout Request
* @return View
*/
public function storeCheckin(AssetCheckinRequest $request)
{
$this->authorize('checkin', Asset::class);
if (! is_array($request->get('ids'))) {
return redirect()->route('hardware')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
}
$asset_ids = array_filter($request->get('ids'));
DB::transaction(function () use ($asset_ids, $request) {
foreach ($asset_ids as $asset_id) {
$asset = Asset::findOrFail($asset_id);
$this->authorize('checkin', $asset);
event(new CheckoutableCheckedIn($asset, '', Auth::user(), $request->input('note')));
}
});
// Get all pending Acceptances for this asset and delete them
$assets = Asset::find($request->input('ids'));
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
[Asset::class],
function (Builder $query) use ($asset) {
$query->where('id', $asset->id);
})->get();
$acceptances->map(function($acceptance) {
$acceptance->delete();
});
return redirect()->to('hardware');
}
}
+17 -48
View File
@@ -68,21 +68,17 @@ class LoginController extends Controller
return redirect()->intended('/');
}
if (!$request->session()->has('loggedout')) {
// If the environment is set to ALWAYS require SAML, go straight to the SAML route.
// We don't need to check other settings, as this should override those.
if (config('app.require_saml')) {
return redirect()->route('saml.login');
}
//If the environment is set to ALWAYS require SAML, go straight to the SAML route.
//We don't need to check other settings, as this should override those.
if(config('app.require_saml')) {
return redirect()->route('saml.login');
}
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == '1' && ! ($request->has('nosaml') || $request->session()->has('error'))) {
return redirect()->route('saml.login');
}
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == '1' && ! ($request->has('nosaml') || $request->session()->has('error'))) {
return redirect()->route('saml.login');
}
if (Setting::getSettings()->login_common_disabled == '1') {
\Log::debug('login_common_disabled is set to 1 - return a 403');
return view('errors.403');
}
@@ -106,17 +102,15 @@ class LoginController extends Controller
{
$saml = $this->saml;
$samlData = $request->session()->get('saml_login');
if ($saml->isEnabled() && ! empty($samlData)) {
try {
Log::debug('Attempting to log user in by SAML authentication.');
$user = $saml->samlLogin($samlData);
if (!is_null($user)) {
if (! is_null($user)) {
Auth::login($user);
} else {
$username = $saml->getUsername();
\Log::debug("SAML user '$username' could not be found in database.");
\Log::warning("SAML user '$username' could not be found in database.");
$request->session()->flash('error', trans('auth/message.signin.error'));
$saml->clearData();
}
@@ -125,25 +119,11 @@ class LoginController extends Controller
$user->last_login = \Carbon::now();
$user->save();
}
} catch (\Exception $e) {
\Log::debug('There was an error authenticating the SAML user: '.$e->getMessage());
\Log::warning('There was an error authenticating the SAML user: '.$e->getMessage());
throw new \Exception($e->getMessage());
}
// Fallthrough with better logging
} else {
// Better logging
if (!$saml->isEnabled()) {
\Log::debug("SAML page requested, but SAML does not seem to enabled.");
} else {
\Log::debug("SAML page requested, but samlData seems empty.");
}
}
}
/**
@@ -181,7 +161,7 @@ class LoginController extends Controller
Log::debug("Local user ".$request->input('username')." does not exist");
Log::debug("Creating local user ".$request->input('username'));
if ($user = Ldap::createUserFromLdap($ldap_user, $request->input('password'))) {
if ($user = Ldap::createUserFromLdap($ldap_user)) { //this handles passwords on its own
Log::debug("Local user created.");
} else {
Log::debug("Could not create local user.");
@@ -255,15 +235,12 @@ class LoginController extends Controller
*/
public function login(Request $request)
{
//If the environment is set to ALWAYS require SAML, return access denied
if (config('app.require_saml')) {
\Log::debug('require SAML is enabled in the .env - return a 403');
if(config('app.require_saml')) {
return view('errors.403');
}
if (Setting::getSettings()->login_common_disabled == '1') {
\Log::debug('login_common_disabled is set to 1 - return a 403');
return view('errors.403');
}
@@ -354,6 +331,7 @@ class LoginController extends Controller
$secret = Google2FA::generateSecretKey();
$user->two_factor_secret = $secret;
$user->save();
$barcode = new Barcode();
$barcode_obj =
@@ -371,8 +349,6 @@ class LoginController extends Controller
[-2, -2, -2, -2]
);
$user->save(); // make sure to save *AFTER* displaying the barcode, or else we might save a two_factor_secret that we never actually displayed to the user if the barcode fails
return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj);
}
@@ -417,7 +393,7 @@ class LoginController extends Controller
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
}
if (! $request->has('two_factor_secret')) { // TODO this seems almost the same as above?
if (! $request->has('two_factor_secret')) {
return redirect()->route('two-factor')->with('error', 'Two-factor code is required.');
}
@@ -445,17 +421,10 @@ class LoginController extends Controller
*/
public function logout(Request $request)
{
// Logout is only allowed with a http POST but we need to allow GET for SAML SLO
$settings = Setting::getSettings();
$saml = $this->saml;
$samlLogout = $request->session()->get('saml_logout');
$sloRedirectUrl = null;
$sloRequestUrl = null;
// Only allow GET if we are doing SAML SLO otherwise abort with 405
if ($request->isMethod('GET') && !$samlLogout) {
abort(405);
}
if ($saml->isEnabled()) {
$auth = $saml->getAuth();
@@ -472,6 +441,8 @@ class LoginController extends Controller
return redirect()->away($sloRequestUrl);
}
$request->session()->regenerate(true);
$request->session()->regenerate(true);
Auth::logout();
@@ -502,7 +473,6 @@ class LoginController extends Controller
]);
}
public function username()
{
return 'username';
@@ -529,7 +499,6 @@ class LoginController extends Controller
->withErrors([$this->username() => $message]);
}
/**
* Override the lockout time and duration
*
@@ -3,11 +3,13 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserRequest;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class ResetPasswordController extends Controller
{
@@ -61,14 +63,6 @@ class ResetPasswordController extends Controller
public function showResetForm(Request $request, $token = null)
{
$credentials = $request->only('email', 'token');
if (is_null($this->broker()->getUser($credentials))) {
\Log::debug('Password reset form FAILED - this token is not valid.');
return redirect()->route('password.request')->with('error', trans('passwords.token'));
}
return view('auth.passwords.reset')->with(
[
'token' => $token,
@@ -79,53 +73,38 @@ class ResetPasswordController extends Controller
public function reset(Request $request)
{
$broker = $this->broker();
$messages = [
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
];
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
\Log::debug('Checking if '.$request->input('username').' exists');
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
if ($user = User::where('username', '=', $request->input('username'))->where('activated', '1')->whereNotNull('email')->first()) {
\Log::debug($user->username.' exists');
// handle the password validation rules set by the admin settings
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== false) {
$request->validate(
[
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"',
], $messages);
}
// set the response
$response = $broker->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
});
// Check if the password reset above actually worked
if ($response == \Password::PASSWORD_RESET) {
\Log::debug('Password reset for '.$user->username.' worked');
return redirect()->guest('login')->with('success', trans('passwords.reset'));
}
\Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
return redirect()->back()->withInput($request->only('email'))->with('error', trans('passwords.token'));
// Check to see if the user even exists
$user = User::where('username', '=', $request->input('username'))->first();
$broker = $this->broker();
if (strpos(Setting::passwordComplexityRulesSaving('store'), 'disallow_same_pwd_as_user_fields') !== false) {
$request->validate(
[
'password' => 'required|notIn:["'.$user->email.'","'.$user->username.'","'.$user->first_name.'","'.$user->last_name.'"',
], $messages);
}
$response = $broker->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
\Log::debug('Password reset for '.$request->input('username').' FAILED - user does not exist or does not have an email address - but make it look like it succeeded');
return redirect()->guest('login')->with('success', trans('passwords.reset'));
return $response == \Password::PASSWORD_RESET
? $this->sendResetResponse($request, $response)
: $this->sendResetFailedResponse($request, $response);
}
protected function sendResetFailedResponse(Request $request, $response)
{
return redirect()->back()
->withInput(['username'=> $request->input('username')])
->withErrors(['username' => trans($response), 'password' => trans($response)]);
}
}
+1 -2
View File
@@ -51,7 +51,6 @@ class SamlController extends Controller
$metadata = $this->saml->getSPMetadata();
if (empty($metadata)) {
\Log::debug('SAML metadata is empty - return a 403');
return response()->view('errors.403', [], 403);
}
@@ -142,6 +141,6 @@ class SamlController extends Controller
return view('errors.403');
}
return redirect()->route('logout')->with(['saml_logout' => true,'saml_slo_redirect_url' => $sloUrl]);
return redirect()->route('logout')->with('saml_slo_redirect_url', $sloUrl);
}
}
@@ -80,7 +80,6 @@ class ComponentsController extends Controller
$component->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
$component->notes = $request->input('notes');
$component = $request->handleImages($component);
@@ -129,7 +128,7 @@ class ComponentsController extends Controller
if (is_null($component = Component::find($componentId))) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
}
$min = $component->numCheckedOut();
$min = $component->numCHeckedOut();
$validator = Validator::make($request->all(), [
'qty' => "required|numeric|min:$min",
]);
@@ -153,7 +152,6 @@ class ComponentsController extends Controller
$component->purchase_date = $request->input('purchase_date');
$component->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$component->qty = $request->input('qty');
$component->notes = $request->input('notes');
$component = $request->handleImages($component);
@@ -9,7 +9,6 @@ use App\Models\Company;
use App\Models\Consumable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Validator;
/**
* This controller handles all actions related to Consumables for
@@ -79,8 +78,6 @@ class ConsumablesController extends Controller
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$consumable->qty = $request->input('qty');
$consumable->user_id = Auth::id();
$consumable->notes = $request->input('notes');
$consumable = $request->handleImages($consumable);
@@ -129,17 +126,6 @@ class ConsumablesController extends Controller
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
$min = $consumable->numCheckedOut();
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$min"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$this->authorize($consumable);
$consumable->name = $request->input('name');
@@ -154,7 +140,6 @@ class ConsumablesController extends Controller
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
$consumable->qty = Helper::ParseFloat($request->input('qty'));
$consumable->notes = $request->input('notes');
$consumable = $request->handleImages($consumable);
@@ -186,7 +186,7 @@ class CustomFieldsetsController extends Controller
}
}
$results = $set->fields()->attach($request->input('field_id'), ['required' => ($request->input('required') == 'on'), 'order' => (int)$request->input('order', 1)]);
$results = $set->fields()->attach($request->input('field_id'), ['required' => ($request->input('required') == 'on'), 'order' => $request->input('order', 1)]);
return redirect()->route('fieldsets.show', [$id])->with('success', trans('admin/custom_fields/message.field.create.assoc_success'));
}
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Kits;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Models\PredefinedKit;
use App\Models\Asset;
use App\Models\PredefinedLicence;
use App\Models\PredefinedModel;
use App\Models\User;
@@ -134,7 +134,6 @@ class LicensesController extends Controller
->with('maintained_list', $maintained_list);
}
/**
* Validates and stores the license form data submitted from the edit
* license form.
+12 -24
View File
@@ -211,35 +211,23 @@ class LocationsController extends Controller
public function print_assigned($id)
{
$location = Location::where('id', $id)->first();
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
}
public function print_all_assigned($id)
{
if ($location = Location::where('id', $id)->first()) {
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
$location = Location::where('id', $id)->first();
$parent = Location::where('id', $location->parent_id)->first();
$manager = User::where('id', $location->manager_id)->first();
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
}
}
+19 -19
View File
@@ -275,18 +275,13 @@ class ReportsController extends Controller
}
}
if($actionlog->item){
$item_name = e($actionlog->item->getDisplayNameAttribute());
} else {
$item_name = '';
}
$row = [
$actionlog->created_at,
($actionlog->user) ? e($actionlog->user->getFullNameAttribute()) : '',
$actionlog->present()->actionType(),
e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
($actionlog->itemType() == 'user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
$target_name,
($actionlog->note) ? e($actionlog->note) : '',
$actionlog->log_meta,
@@ -642,10 +637,6 @@ class ReportsController extends Controller
if (($request->filled('next_audit_start')) && ($request->filled('next_audit_end'))) {
$assets->whereBetween('assets.next_audit_date', [$request->input('next_audit_start'), $request->input('next_audit_end')]);
}
if($request->filled('exclude_archived')){
$assets->notArchived();
}
$assets->orderBy('assets.id', 'ASC')->chunk(20, function ($assets) use ($handle, $customfields, $request) {
$executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
@@ -942,17 +933,12 @@ class ReportsController extends Controller
/**
* 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' => function ($query) {
$query->withTrashed();
}, 'checkoutable.assignedTo', 'checkoutable.model'])->get();
}
$acceptances = CheckoutAcceptance::pending()->with('assignedTo')->get();
$assetsForReport = $acceptances
->filter(function ($acceptance) {
return $acceptance->checkoutable_type == 'App\Models\Asset';
->filter(function($acceptance) {
return $acceptance->checkoutable_type == 'App\Models\Asset' && !is_null($acceptance->assignedTo);
})
->map(function($acceptance) {
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
@@ -1152,4 +1138,18 @@ class ReportsController extends Controller
$this->getModelsInCategoriesThatRequireAcceptance($this->getCategoriesThatRequireAcceptance())
);
}
/**
* getAssetsNotAcceptedYet
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getAssetsNotAcceptedYet()
{
$this->authorize('reports.view');
return Asset::unaccepted();
}
}
+49 -114
View File
@@ -25,7 +25,6 @@ use Response;
use App\Http\Requests\SlackSettingsRequest;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Artisan;
use Validator;
/**
* This controller handles all actions related to Settings for
@@ -911,24 +910,7 @@ class SettingsController extends Controller
{
$setting = Setting::getSettings();
/**
* This validator is only temporary (famous last words.) - @snipe
*/
$messages = [
'ldap_username_field.not_in' => '<code>sAMAccountName</code> (mixed case) will likely not work. You should use <code>samaccountname</code> (lowercase) instead. ',
'ldap_auth_filter_query.not_in' => '<code>uid=samaccountname</code> is probably not a valid auth filter. You probably want <code>uid=</code> ',
'ldap_filter.regex' => 'This value should probably not be wrapped in parentheses.',
];
$validator = Validator::make($setting->toArray(), [
'ldap_username_field' => 'not_in:sAMAccountName',
'ldap_auth_filter_query' => 'not_in:uid=samaccountname',
'ldap_filter' => 'regex:"^[^(]"',
], $messages);
return view('settings.ldap', compact('setting'))->withErrors($validator);
return view('settings.ldap', compact('setting'));
}
/**
@@ -960,11 +942,10 @@ class SettingsController extends Controller
$setting->ldap_lname_field = $request->input('ldap_lname_field');
$setting->ldap_fname_field = $request->input('ldap_fname_field');
$setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query');
$setting->ldap_version = $request->input('ldap_version', 3);
$setting->ldap_version = $request->input('ldap_version');
$setting->ldap_active_flag = $request->input('ldap_active_flag');
$setting->ldap_emp_num = $request->input('ldap_emp_num');
$setting->ldap_email = $request->input('ldap_email');
$setting->ldap_manager = $request->input('ldap_manager');
$setting->ad_domain = $request->input('ad_domain');
$setting->is_ad = $request->input('is_ad', '0');
$setting->ad_append_domain = $request->input('ad_append_domain', '0');
@@ -1044,12 +1025,6 @@ class SettingsController extends Controller
return redirect()->back()->withInput()->withErrors($setting->getErrors());
}
public static function getPDFBranding()
{
$pdf_branding= Setting::getSettings();
return $pdf_branding;
}
/**
* Show the listing of backups.
@@ -1062,7 +1037,7 @@ class SettingsController extends Controller
*/
public function getBackups()
{
$settings = Setting::getSettings();
$path = 'app/backups';
$backup_files = Storage::files($path);
$files_raw = [];
@@ -1079,7 +1054,7 @@ class SettingsController extends Controller
'filename' => basename($backup_files[$f]),
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
'modified_value' => $file_timestamp,
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
'modified_display' => Helper::getFormattedDateObject($file_timestamp, $type = 'datetime', false),
];
}
@@ -1165,31 +1140,23 @@ class SettingsController extends Controller
*/
public function deleteFile($filename = null)
{
if (config('app.allow_backup_delete')=='true') {
if (! config('app.lock_passwords')) {
$path = 'app/backups';
if (!config('app.lock_passwords')) {
$path = 'app/backups';
if (Storage::exists($path.'/'.$filename)) {
try {
Storage::delete($path.'/'.$filename);
if (Storage::exists($path . '/' . $filename)) {
try {
Storage::delete($path . '/' . $filename);
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted'));
} catch (\Exception $e) {
\Log::debug($e);
}
} else {
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted'));
} catch (\Exception $e) {
\Log::debug($e);
}
} else {
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
}
} else {
return redirect()->route('settings.backups.index')->with('error', trans('general.feature_disabled'));
}
// Hell to the no
\Log::warning('User ID '.Auth::user()->id.' is attempting to delete backup file '.$filename.' and is not authorized to.');
return redirect()->route('settings.backups.index')->with('error', trans('general.backup_delete_not_allowed'));
}
@@ -1224,10 +1191,9 @@ class SettingsController extends Controller
Storage::putFileAs('app/backups', $request->file('file'), $upload_filename);
return redirect()->route('settings.backups.index')->with('success', 'File uploaded');
} else {
return redirect()->route('settings.backups.index')->withErrors($request->getErrors());
}
return redirect()->route('settings.backups.index')->withErrors($request->getErrors());
}
} else {
@@ -1261,11 +1227,7 @@ class SettingsController extends Controller
// TODO: run a backup
Artisan::call('db:wipe', [
'--force' => true,
]);
\Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
Artisan::call('db:wipe');
// run the restore command
Artisan::call('snipeit:restore',
@@ -1277,31 +1239,28 @@ class SettingsController extends Controller
// If it's greater than 300, it probably worked
$output = Artisan::output();
if (strlen($output) > 300) {
$find_user = DB::table('users')->where('first_name', $user->first_name)->where('last_name', $user->last_name)->exists();
if(!$find_user){
\Log::warning('Attempting to restore user: ' . $user->first_name . ' ' . $user->last_name);
$new_user = $user->replicate();
$new_user->push();
}
/* Run migrations */
\Log::debug('Migrating database...');
Artisan::call('migrate', ['--force' => true]);
$migrate_output = Artisan::output();
\Log::debug($migrate_output);
$session_files = glob(storage_path("framework/sessions/*"));
foreach ($session_files as $file) {
if (is_file($file))
unlink($file);
}
DB::table('users')->update(['remember_token' => null]);
\Auth::logout();
$find_user = DB::table('users')->where('username', $user->username)->exists();
if (!$find_user){
\Log::warning('Attempting to restore user: ' . $user->username);
$new_user = $user->replicate();
$new_user->push();
return redirect()->route('login')->with('success', 'Your system has been restored. Please login again.');
} else {
\Log::debug('User: ' . $user->username .' already exists.');
return redirect()->route('settings.backups.index')->with('error', $output);
}
\Log::debug('Logging all users out..');
Artisan::call('snipeit:global-logout', ['--force' => true]);
DB::table('users')->update(['remember_token' => null]);
\Auth::logout();
return redirect()->route('login')->with('success', 'Your system has been restored. Please login again.');
} else {
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
}
@@ -1321,15 +1280,9 @@ class SettingsController extends Controller
*/
public function getPurge()
{
\Log::warning('User ID '.Auth::user()->id.' is attempting a PURGE');
\Log::warning('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting a PURGE');
if (config('app.allow_purge')=='true') {
return view('settings.purge-form');
}
return redirect()->route('settings.index')->with('error', trans('general.purge_not_allowed'));
return view('settings.purge-form');
}
/**
@@ -1343,40 +1296,22 @@ class SettingsController extends Controller
*/
public function postPurge(Request $request)
{
\Log::warning('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting a PURGE');
if (! config('app.lock_passwords')) {
if ('DELETE' == $request->input('confirm_purge')) {
\Log::warning('User ID '.Auth::user()->id.' initiated a PURGE!');
// Run a backup immediately before processing
Artisan::call('backup:run');
Artisan::call('snipeit:purge', ['--force' => 'true', '--no-interaction' => true]);
$output = Artisan::output();
if (config('app.allow_purge')=='true') {
\Log::debug('Purging is not allowed via the .env');
if (!config('app.lock_passwords')) {
if ($request->input('confirm_purge')=='DELETE') {
\Log::warning('User ID ' . Auth::user()->id . ' initiated a PURGE!');
// Run a backup immediately before processing
Artisan::call('backup:run');
Artisan::call('snipeit:purge', ['--force' => 'true', '--no-interaction' => true]);
$output = Artisan::output();
return redirect()->route('settings.index')
->with('output', $output)->with('success', trans('admin/settings/message.purge.success'));
} else {
return redirect()->route('settings.purge.index')
->with('error', trans('admin/settings/message.purge.validation_failed'));
}
return view('settings/purge')
->with('output', $output)->with('success', trans('admin/settings/message.purge.success'));
} else {
return redirect()->route('settings.index')
->with('error', trans('general.feature_disabled'));
return redirect()->back()->with('error', trans('admin/settings/message.purge.validation_failed'));
}
} else {
return redirect()->back()->with('error', trans('general.feature_disabled'));
}
\Log::error('User '.Auth::user()->username.' (ID'.Auth::user()->id.') is attempting to purge deleted data and is not authorized to.');
// Nope.
return redirect()->route('settings.index')
->with('error', trans('general.purge_not_allowed'));
}
/**
@@ -46,13 +46,13 @@ class BulkUsersController extends Controller
foreach ($users as $user) {
if (($user->activated == '1') && ($user->email != '')) {
$credentials = ['email' => $user->email];
Password::sendResetLink($credentials/* , function (Message $message) {
$message->subject($this->getEmailSubject()); // TODO - I'm not sure if we still need this, but this second parameter is no longer accepted in later Laravel versions.
} */ ); // TODO - so hopefully this doesn't give us generic password reset messages? But it at least _works_
Password::sendResetLink($credentials, function (Message $message) {
$message->subject($this->getEmailSubject());
});
}
}
return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent'));
return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent'));
}
}
@@ -90,11 +90,7 @@ class BulkUsersController extends Controller
->conditionallyAddItem('department_id')
->conditionallyAddItem('company_id')
->conditionallyAddItem('locale')
->conditionallyAddItem('remote')
->conditionallyAddItem('ldap_import')
->conditionallyAddItem('activated');
// If the manager_id is one of the users being updated, generate a warning.
if (array_search($request->input('manager_id'), $user_raw_array)) {
$manager_conflict = true;
@@ -105,16 +101,11 @@ class BulkUsersController extends Controller
if (! $manager_conflict) {
$this->conditionallyAddItem('manager_id');
}
// Save the updated info
User::whereIn('id', $user_raw_array)
->where('id', '!=', Auth::id())->update($this->update_array);
if (array_key_exists('location_id', $this->update_array)){
Asset::where('assigned_type', User::class)
->whereIn('assigned_to', $user_raw_array)
->update(['location_id' => $this->update_array['location_id']]);
}
// Only sync groups if groups were selected
if ($request->filled('groups')) {
foreach ($users as $user) {
@@ -180,7 +171,6 @@ class BulkUsersController extends Controller
$accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get();
$licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get();
$this->logItemCheckinAndDelete($assets, Asset::class);
$this->logItemCheckinAndDelete($accessories, Accessory::class);
$this->logItemCheckinAndDelete($licenses, LicenseSeat::class);
@@ -191,7 +181,6 @@ class BulkUsersController extends Controller
'assigned_type' => null,
]);
LicenseSeat::whereIn('id', $licenses->pluck('id'))->update(['assigned_to' => null]);
foreach ($users as $user) {
+13 -39
View File
@@ -23,7 +23,6 @@ use Redirect;
use Str;
use Symfony\Component\HttpFoundation\StreamedResponse;
use View;
use App\Notifications\CurrentInventory;
/**
* This controller handles all actions related to Users for
@@ -94,8 +93,8 @@ class UsersController extends Controller
$this->authorize('create', User::class);
$user = new User;
//Username, email, and password need to be handled specially because the need to respect config values on an edit.
$user->email = trim($request->input('email'));
$user->username = trim($request->input('username'));
$user->email = e($request->input('email'));
$user->username = e($request->input('username'));
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
@@ -116,9 +115,6 @@ class UsersController extends Controller
$user->state = $request->input('state', null);
$user->country = $request->input('country', null);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->website = $request->input('website', null);
$user->created_by = Auth::user()->id;
// Strip out the superuser permission if the user isn't a superadmin
$permissions_array = $request->input('permission');
@@ -183,6 +179,7 @@ class UsersController extends Controller
if ($user = User::find($id)) {
$this->authorize('update', $user);
$permissions = config('permissions');
$groups = Group::pluck('name', 'id');
$userGroups = $user->groups()->pluck('name', 'id');
@@ -193,7 +190,9 @@ class UsersController extends Controller
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user);
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
$error = trans('admin/users/message.user_not_found', compact('id'));
return redirect()->route('users.index')->with('error', $error);
}
/**
@@ -246,9 +245,9 @@ class UsersController extends Controller
// Update the user
if ($request->filled('username')) {
$user->username = trim($request->input('username'));
$user->username = $request->input('username');
}
$user->email = trim($request->input('email'));
$user->email = $request->input('email');
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
@@ -268,8 +267,6 @@ class UsersController extends Controller
$user->country = $request->input('country', null);
$user->activated = $request->input('activated', 0);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->website = $request->input('website', null);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
@@ -616,30 +613,6 @@ class UsersController extends Controller
->with('settings', Setting::getSettings());
}
/**
* Emails user a list of assigned assets
*
* @author [G. Martinez] [<godmartinz@gmail.com>]
* @since [v6.0.5]
* @param \App\Http\Controllers\Users\UsersController $id
* @return \Illuminate\Http\RedirectResponse
*/
public function emailAssetList($id)
{
$this->authorize('view', User::class);
if (!$user = User::find($id)) {
return redirect()->back()
->with('error', trans('admin/users/message.user_not_found', ['id' => $id]));
}
if (empty($user->email)) {
return redirect()->back()->with('error', trans('admin/users/message.user_has_no_email'));
}
$user->notify((new CurrentInventory($user)));
return redirect()->back()->with('success', trans('admin/users/general.user_notified'));
}
/**
* Send individual password reset email
*
@@ -650,11 +623,12 @@ class UsersController extends Controller
public function sendPasswordReset($id)
{
if (($user = User::find($id)) && ($user->activated == '1') && ($user->email != '') && ($user->ldap_import == '0')) {
$credentials = ['email' => trim($user->email)];
$credentials = ['email' => $user->email];
try {
Password::sendResetLink($credentials);
\Password::sendResetLink($credentials, function (Message $message) use ($user) {
$message->subject($this->getEmailSubject());
});
return redirect()->back()->with('success', trans('admin/users/message.password_reset_sent', ['email' => $user->email]));
} catch (\Exception $e) {
@@ -664,4 +638,4 @@ class UsersController extends Controller
return redirect()->back()->with('error', 'User is not activated, is LDAP synced, or does not have an email address ');
}
}
}
@@ -180,4 +180,123 @@ class ViewAssetsController extends Controller
{
return view('account/requested');
}
// Get the acceptance screen
public function getAcceptAsset($logID = null)
{
$findlog = Actionlog::where('id', $logID)->first();
if (! $findlog) {
return redirect()->to('account/view-assets')->with('error', 'No matching record.');
}
if ($findlog->accepted_id != '') {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
}
$user = Auth::user();
// TODO - Fix this for non-assets
if (($findlog->item_type == Asset::class) && ($user->id != $findlog->item->assigned_to)) {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
$item = $findlog->item;
// Check if the asset exists
if (is_null($item)) {
// Redirect to the asset management page
return redirect()->to('account')->with('error', trans('admin/hardware/message.does_not_exist'));
} elseif (! Company::isCurrentUserHasAccess($item)) {
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
} else {
return view('account/accept-asset', compact('item'))->with('findlog', $findlog)->with('item', $item);
}
}
// Save the acceptance
public function postAcceptAsset(Request $request, $logID = null)
{
// Check if the asset exists
if (is_null($findlog = Actionlog::where('id', $logID)->first())) {
// Redirect to the asset management page
return redirect()->to('account/view-assets')->with('error', trans('admin/hardware/message.does_not_exist'));
}
if ($findlog->accepted_id != '') {
// Redirect to the asset management page
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
}
if ($request->missing('asset_acceptance')) {
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
}
$user = Auth::user();
if (($findlog->item_type == Asset::class) && ($user->id != $findlog->item->assigned_to)) {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
if ($request->filled('signature_output')) {
$path = config('app.private_uploads').'/signatures';
$sig_filename = 'siglog-'.$findlog->id.'-'.date('Y-m-d-his').'.png';
$data_uri = e($request->get('signature_output'));
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
Storage::putFileAs($path, $decoded_image, $sig_filename);
//file_put_contents($path.'/'.$sig_filename, $decoded_image);
}
$logaction = new Actionlog();
if ($request->input('asset_acceptance') == 'accepted') {
$logaction_msg = 'accepted';
$accepted = 'accepted';
$return_msg = trans('admin/users/message.accepted');
} else {
$logaction_msg = 'declined';
$accepted = 'rejected';
$return_msg = trans('admin/users/message.declined');
}
$logaction->item_id = $findlog->item_id;
$logaction->item_type = $findlog->item_type;
// Asset
if (($findlog->item_id != '') && ($findlog->item_type == Asset::class)) {
if ($request->input('asset_acceptance') != 'accepted') {
DB::table('assets')
->where('id', $findlog->item_id)
->update(['assigned_to' => null]);
}
}
$logaction->target_id = $findlog->target_id;
$logaction->target_type = User::class;
$logaction->note = e($request->input('note'));
$logaction->updated_at = date('Y-m-d H:i:s');
if (isset($sig_filename)) {
$logaction->accept_signature = $sig_filename;
}
$log = $logaction->logaction($logaction_msg);
$update_checkout = DB::table('action_logs')
->where('id', $findlog->id)
->update(['accepted_id' => $logaction->id]);
if (($findlog->item_id != '') && ($findlog->item_type == Asset::class)) {
$affected_asset = $logaction->item;
$affected_asset->accepted = $accepted;
$affected_asset->save();
}
if ($update_checkout) {
return redirect()->to('account/view-assets')->with('success', $return_msg);
} else {
return redirect()->to('account/view-assets')->with('error', 'Something went wrong ');
}
}
}
+1 -1
View File
@@ -39,13 +39,13 @@ class Kernel extends HttpKernel
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\CheckLocale::class,
\App\Http\Middleware\CheckUserIsActivated::class,
\App\Http\Middleware\CheckForTwoFactor::class,
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
\App\Http\Middleware\AssetCountForSidebar::class,
],
'api' => [
'throttle:120,1',
'auth:api',
],
];
@@ -4,9 +4,8 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Auth;
class CheckUserIsActivated
class Authenticate
{
/**
* The Guard implementation.
@@ -35,16 +34,14 @@ class CheckUserIsActivated
*/
public function handle($request, Closure $next)
{
// If there is a user AND the user is NOT activated, send them to the login page
// This prevents people who still have active sessions logged in and their status gets toggled
// to inactive (aka unable to login)
if (($request->user()) && (!$request->user()->isActivated())) {
Auth::logout();
return redirect()->guest('login');
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}
+1 -7
View File
@@ -24,13 +24,7 @@ class CheckForTwoFactor
public function handle($request, Closure $next)
{
// Skip the logic if the user is on the two factor pages or the setup pages
// TODO - what we have below only works because our ROUTE uri's look _exactly_ like the route *names*.
// The problem is that, in the new(-ish) Laravel routing system, the route-name doesn't match if the route _verb_ is wrong.
// so we can have a blade that POST's to a route('two-factor') - but that route *name* is only matched when the method is GET
// because we attached the name to the GET, not to the POST (as route names *SHOULD* be unique in Laravel)
// there has got to be a better way to do this, but this is the best I could come up with for now.
if (in_array($request->route()->getName(), self::IGNORE_ROUTES) || in_array($request->route()->uri(), self::IGNORE_ROUTES)) {
if (in_array($request->route()->getName(), self::IGNORE_ROUTES)) {
return $next($request);
}
+15
View File
@@ -42,15 +42,30 @@ class SecurityHeaders
// - https://github.com/w3c/webappsec-feature-policy/issues/189
$feature_policy[] = "accelerometer 'none'";
$feature_policy[] = "ambient-light-sensor 'none'";
$feature_policy[] = "animations 'none'";
$feature_policy[] = "autoplay 'none'";
$feature_policy[] = "battery 'none'";
$feature_policy[] = "camera 'none'";
$feature_policy[] = "display-capture 'none'";
$feature_policy[] = "document-domain 'none'";
$feature_policy[] = "encrypted-media 'none'";
$feature_policy[] = "fullscreen 'none'";
$feature_policy[] = "geolocation 'none'";
$feature_policy[] = "gyroscope 'none'";
$feature_policy[] = "legacy-image-formats 'none'";
$feature_policy[] = "magnetometer 'none'";
$feature_policy[] = "microphone 'none'";
$feature_policy[] = "midi 'none'";
$feature_policy[] = "oversized-images 'none'";
$feature_policy[] = "payment 'none'";
$feature_policy[] = "picture-in-picture 'none'";
$feature_policy[] = "publickey-credentials 'none'";
$feature_policy[] = "sync-xhr 'none'";
$feature_policy[] = "unsized-media 'none'";
$feature_policy[] = "usb 'none'";
$feature_policy[] = "vibrate 'none'";
$feature_policy[] = "wake-lock 'none'";
$feature_policy[] = "xr-spatial-tracking 'none'";
$feature_policy = implode(';', $feature_policy);
@@ -25,7 +25,6 @@ class AssetCheckoutRequest extends Request
'assigned_user' => 'required_without_all:assigned_asset,assigned_location',
'assigned_asset' => 'required_without_all:assigned_user,assigned_location',
'assigned_location' => 'required_without_all:assigned_user,assigned_asset',
'status_id' => 'exists:status_labels,id,deployable,1',
'checkout_to_type' => 'required|in:asset,location,user',
];
+2 -2
View File
@@ -60,8 +60,8 @@ class ItemImportRequest extends FormRequest
}
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
->setUserId(Auth::id())
->setUpdating($this->get('import-update'))
->setShouldNotify($this->get('send-welcome'))
->setUpdating($this->has('import-update'))
->setShouldNotify($this->has('send-welcome'))
->setUsernameFormat('firstname.lastname')
->setFieldMappings($fieldMappings);
$importer->import();
@@ -68,6 +68,8 @@ class AccessoriesTransformer
$array = [];
foreach ($accessory_users as $user) {
\Log::debug(print_r($user->pivot, true));
\Log::debug(print_r($user->pivot, true));
$array[] = [
'assigned_pivot_id' => $user->pivot->id,
+55 -60
View File
@@ -1,4 +1,5 @@
<?php
namespace App\Http\Transformers;
use App\Helpers\Helper;
@@ -8,82 +9,82 @@ use Illuminate\Database\Eloquent\Collection;
class ActionlogsTransformer
{
public function transformActionlogs (Collection $actionlogs, $total)
public function transformActionlogs(Collection $actionlogs, $total)
{
$array = array();
$array = [];
$settings = Setting::getSettings();
foreach ($actionlogs as $actionlog) {
$array[] = self::transformActionlog($actionlog, $settings);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
private function clean_field($value)
{
// This object stuff is weird, and is used to make up for the fact that
// older data can get strangely formatted if an asset existed,
// then a new custom field is added, and the asset is saved again.
// It can result in funnily-formatted strings like:
//
// {"_snipeit_right_sized_fault_tolerant_localareanetwo_1":
// {"old":null,"new":{"value":"1579490695972","_snipeit_new_field_2":2,"_snipeit_new_field_3":"Monday, 20 January 2020 2:24:55 PM"}}
// so we have to walk down that next level
if(is_object($value) && isset($value->value)) {
return $this->clean_field($value->value);
}
return is_scalar($value) || is_null($value) ? e($value) : e(json_encode($value));
}
public function transformActionlog (Actionlog $actionlog, $settings = null)
public function transformActionlog(Actionlog $actionlog, $settings = null)
{
$icon = $actionlog->present()->icon();
if ($actionlog->filename!='') {
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
if ($actionlog->filename != '') {
$icon = e(Helper::filetype_icon($actionlog->filename));
}
// This is necessary since we can't escape special characters within a JSON object
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
if (($actionlog->log_meta) && ($actionlog->log_meta != '')) {
$meta_array = json_decode($actionlog->log_meta);
if ($meta_array) {
foreach ($meta_array as $fieldname => $fieldata) {
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
}
foreach ($meta_array as $key => $value) {
foreach ($value as $meta_key => $meta_value) {
if (is_array($meta_value)) {
foreach ($meta_value as $meta_value_key => $meta_value_value) {
if (is_scalar($meta_value_value)) {
$clean_meta[$key][$meta_value_key] = e($meta_value_value);
} else {
$clean_meta[$key][$meta_value_key] = 'invalid scalar: '.print_r($meta_value_value, true);
}
}
} else {
}
}
// This object stuff is weird, and is used to make up for the fact that
// older data can get strangely formatted if an asset existed,
// then a new custom field is added, and the asset is saved again.
// It can result in funnily-formatted strings like:
//
// {"_snipeit_right_sized_fault_tolerant_localareanetwo_1":
// {"old":null,"new":{"value":"1579490695972","_snipeit_new_field_2":2,"_snipeit_new_field_3":"Monday, 20 January 2020 2:24:55 PM"}}
// so we have to walk down that next level
$file_url = '';
if($actionlog->filename!='') {
if ($actionlog->action_type == 'accepted') {
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
} else {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'license') {
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'user') {
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
if (is_object($meta_value)) {
foreach ($meta_value as $meta_value_key => $meta_value_value) {
if ($meta_value_key == 'value') {
$clean_meta[$key]['old'] = null;
$clean_meta[$key]['new'] = e($meta_value->value);
} else {
$clean_meta[$meta_value_key]['old'] = null;
$clean_meta[$meta_value_key]['new'] = e($meta_value_value);
}
}
} else {
$clean_meta[$key][$meta_key] = e($meta_value);
}
}
}
}
}
}
$array = [
$array = [
'id' => (int) $actionlog->id,
'icon' => $icon,
'file' => ($actionlog->filename!='')
?
'file' => ($actionlog->filename != '') ?
[
'url' => $file_url,
'url' => route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]),
'filename' => $actionlog->filename,
'inlineable' => (bool) Helper::show_file_inline($actionlog->filename),
] : null,
'item' => ($actionlog->item) ? [
'id' => (int) $actionlog->item->id,
'name' => ($actionlog->itemType()=='user') ? e($actionlog->item->getFullNameAttribute()) : e($actionlog->item->getDisplayNameAttribute()),
'name' => ($actionlog->itemType() == 'user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
'type' => e($actionlog->itemType()),
] : null,
'location' => ($actionlog->location) ? [
@@ -92,18 +93,18 @@ class ActionlogsTransformer
] : null,
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date'): null,
'next_audit_date' => ($actionlog->itemType() == 'asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date') : null,
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
'action_type' => $actionlog->present()->actionType(),
'admin' => ($actionlog->user) ? [
'id' => (int) $actionlog->user->id,
'name' => e($actionlog->user->getFullNameAttribute()),
'first_name'=> e($actionlog->user->first_name),
'last_name'=> e($actionlog->user->last_name)
'last_name'=> e($actionlog->user->last_name),
] : null,
'target' => ($actionlog->target) ? [
'id' => (int) $actionlog->target->id,
'name' => ($actionlog->targetType()=='user') ? e($actionlog->target->getFullNameAttribute()) : e($actionlog->target->getDisplayNameAttribute()),
'name' => ($actionlog->targetType() == 'user') ? e($actionlog->target->getFullNameAttribute()) : e($actionlog->target->getDisplayNameAttribute()),
'type' => e($actionlog->targetType()),
] : null,
@@ -111,25 +112,19 @@ class ActionlogsTransformer
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
];
//\Log::info("Clean Meta is: ".print_r($clean_meta,true));
//dd($array);
];
return $array;
}
public function transformCheckedoutActionlog (Collection $accessories_users, $total)
public function transformCheckedoutActionlog(Collection $accessories_users, $total)
{
$array = array();
$array = [];
foreach ($accessories_users as $user) {
$array[] = (new UsersTransformer)->transformUser($user);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
}
}
+7 -28
View File
@@ -4,7 +4,6 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Asset;
use App\Models\Setting;
use Gate;
use Illuminate\Database\Eloquent\Collection;
@@ -22,9 +21,6 @@ class AssetsTransformer
public function transformAsset(Asset $asset)
{
// This uses the getSettings() method so we're pulling from the cache versus querying the settings on single asset
$setting = Setting::getSettings();
$array = [
'id' => (int) $asset->id,
'name' => e($asset->name),
@@ -69,8 +65,6 @@ class AssetsTransformer
'name'=> e($asset->defaultLoc->name),
] : 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,
'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null,
'assigned_to' => $this->transformAssignedTo($asset),
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
@@ -94,40 +88,25 @@ class AssetsTransformer
$fields_array = [];
foreach ($asset->model->fieldset->fields as $field) {
if ($field->isFieldDecryptable($asset->{$field->db_column})) {
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
if ($field->isFieldDecryptable($asset->{$field->convertUnicodeDbSlug()})) {
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->convertUnicodeDbSlug()});
$value = (Gate::allows('superadmin')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
if ($field->format == 'DATE'){
if (Gate::allows('superadmin')){
$value = Helper::getFormattedDateObject($value, 'date', false);
} else {
$value = strtoupper(trans('admin/custom_fields/general.encrypted'));
}
}
$fields_array[$field->name] = [
'field' => e($field->db_column),
'field' => e($field->convertUnicodeDbSlug()),
'value' => e($value),
'field_format' => $field->format,
'element' => $field->element,
];
} else {
$value = $asset->{$field->db_column};
if (($field->format == 'DATE') && (!is_null($value)) && ($value!='')){
$value = Helper::getFormattedDateObject($value, 'date', false);
}
$fields_array[$field->name] = [
'field' => e($field->db_column),
'value' => e($value),
'field' => e($field->convertUnicodeDbSlug()),
'value' => e($asset->{$field->convertUnicodeDbSlug()}),
'field_format' => $field->format,
'element' => $field->element,
];
}
}
$array['custom_fields'] = $fields_array;
}
} else {
@@ -39,7 +39,7 @@ class ComponentsAssetsTransformer
if ($asset->model->fieldset) {
foreach ($asset->model->fieldset->fields as $field) {
$fields_array = [$field->name => $asset->{$field->db_column}];
$fields_array = [$field->name => $asset->{$field->convertUnicodeDbSlug()}];
$array += $fields_array;
}
}
@@ -45,7 +45,6 @@ class ComponentsTransformer
'id' => (int) $component->company->id,
'name' => e($component->company->name),
] : null,
'notes' => ($component->notes) ? e($component->notes) : null,
'created_at' => Helper::getFormattedDateObject($component->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($component->updated_at, 'datetime'),
'user_can_checkout' => ($component->numRemaining() > 0) ? 1 : 0,
@@ -38,7 +38,6 @@ class ConsumablesTransformer
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'),
'qty' => (int) $consumable->qty,
'notes' => ($consumable->notes) ? e($consumable->notes) : null,
'created_at' => Helper::getFormattedDateObject($consumable->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($consumable->updated_at, 'datetime'),
];
@@ -46,7 +46,7 @@ class CustomFieldsTransformer
'field_values' => ($field->field_values) ? e($field->field_values) : null,
'field_values_array' => ($field->field_values) ? explode("\r\n", e($field->field_values)) : null,
'type' => e($field->element),
'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false,
'required' => $field->pivot ? $field->pivot->required : false,
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
];
@@ -98,7 +98,7 @@ class DepreciationReportTransformer
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
'book_value' => Helper::formatCurrencyOutput($depreciated_value),
'monthly_depreciation' => $monthly_depreciation,
'checked_out_to' => ($checkout_target) ? e($checkout_target) : null,
'checked_out_to' => $checkout_target,
'diff' => Helper::formatCurrencyOutput($diff),
'number_of_months' => ($asset->model && $asset->model->depreciation) ? e($asset->model->depreciation->months) : null,
'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? e($asset->model->depreciation->name) : null,
@@ -9,14 +9,14 @@ use Illuminate\Database\Eloquent\Collection;
class DepreciationsTransformer
{
public function transformDepreciations(Collection $depreciations, $total)
public function transformDepreciations(Collection $depreciations)
{
$array = [];
foreach ($depreciations as $depreciation) {
$array[] = self::transformDepreciation($depreciation);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
return (new DatatablesTransformer)->transformDatatables($array);
}
public function transformDepreciation(Depreciation $depreciation)
@@ -27,7 +27,8 @@ class DepreciationsTransformer
'months' => $depreciation->months.' '.trans('general.months'),
'depreciation_min' => $depreciation->depreciation_min,
'created_at' => Helper::getFormattedDateObject($depreciation->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime')
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime'),
'depreciation_min' =>($depreciation->depreciation_min),
];
$permissions_array['available_actions'] = [
@@ -39,4 +40,4 @@ class DepreciationsTransformer
return $array;
}
}
}
@@ -28,7 +28,6 @@ class UsersTransformer
'first_name' => e($user->first_name),
'last_name' => e($user->last_name),
'username' => e($user->username),
'remote' => ($user->remote == '1') ? true : false,
'locale' => ($user->locale) ? e($user->locale) : null,
'employee_num' => e($user->employee_num),
'manager' => ($user->manager) ? [
@@ -63,10 +62,6 @@ class UsersTransformer
'accessories_count' => (int) $user->accessories_count,
'consumables_count' => (int) $user->consumables_count,
'company' => ($user->company) ? ['id' => (int) $user->company->id, 'name'=> e($user->company->name)] : null,
'created_by' => ($user->createdBy) ? [
'id' => (int) $user->createdBy->id,
'name'=> e($user->createdBy->present()->fullName),
] : null,
'created_at' => Helper::getFormattedDateObject($user->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($user->updated_at, 'datetime'),
'last_login' => Helper::getFormattedDateObject($user->last_login, 'datetime'),
+1 -4
View File
@@ -39,7 +39,6 @@ class AssetImporter extends ItemImporter
}
}
$this->createAssetIfNotExists($row);
}
@@ -97,12 +96,10 @@ class AssetImporter extends ItemImporter
$item['rtd_location_id'] = $this->item['location_id'];
}
$item['last_audit_date'] = null;
if (isset($this->item['last_audit_date'])) {
$item['last_audit_date'] = $this->item['last_audit_date'];
}
$item['next_audit_date'] = null;
if (isset($this->item['next_audit_date'])) {
$item['next_audit_date'] = $this->item['next_audit_date'];
}
@@ -130,7 +127,7 @@ class AssetImporter extends ItemImporter
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
//-- the class that needs to use it (command importer or GUI importer inside the project).
if (isset($target)) {
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'));
$asset->fresh()->checkOut($target, $this->user_id);
}
return;
+3 -11
View File
@@ -35,7 +35,7 @@ class LicenseImporter extends ItemImporter
->first();
if ($license) {
if (! $this->updating) {
$this->log('A matching License '.$this->item['name'].' with serial '.$this->item['serial'].' already exists');
$this->log('A matching License '.$this->item['name'].'with serial '.$this->item['serial'].' already exists');
return;
}
@@ -47,22 +47,14 @@ class LicenseImporter extends ItemImporter
$license = new License;
}
$asset_tag = $this->item['asset_tag'] = $this->findCsvMatch($row, 'asset_tag'); // used for checkout out to an asset.
$this->item["expiration_date"] = null;
if ($this->findCsvMatch($row, "expiration_date")!='') {
$this->item["expiration_date"] = date("Y-m-d 00:00:01", strtotime($this->findCsvMatch($row, "expiration_date")));
}
$this->item['expiration_date'] = $this->findCsvMatch($row, 'expiration_date');
$this->item['license_email'] = $this->findCsvMatch($row, 'license_email');
$this->item['license_name'] = $this->findCsvMatch($row, 'license_name');
$this->item['maintained'] = $this->findCsvMatch($row, 'maintained');
$this->item['purchase_order'] = $this->findCsvMatch($row, 'purchase_order');
$this->item['reassignable'] = $this->findCsvMatch($row, 'reassignable');
$this->item['seats'] = $this->findCsvMatch($row, 'seats');
$this->item["termination_date"] = null;
if ($this->findCsvMatch($row, "termination_date")!='') {
$this->item["termination_date"] = date("Y-m-d 00:00:01", strtotime($this->findCsvMatch($row, "termination_date")));
}
$this->item['termination_date'] = $this->findCsvMatch($row, 'termination_date');
if ($editingLicense) {
$license->update($this->sanitizeItemForUpdating($license));
-15
View File
@@ -2,9 +2,7 @@
namespace App\Importer;
use App\Models\Asset;
use App\Models\Department;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\WelcomeNotification;
@@ -62,13 +60,6 @@ class UserImporter extends ItemImporter
if ($this->shouldUpdateField($user_department)) {
$this->item['department_id'] = $this->createOrFetchDepartment($user_department);
}
if (is_null($this->item['username']) || $this->item['username'] == "") {
$user_full_name = $this->item['first_name'] . ' ' . $this->item['last_name'];
$user_formatted_array = User::generateFormattedNameFromFullName($user_full_name, Setting::getSettings()->username_format);
$this->item['username'] = $user_formatted_array['username'];
}
$user = User::where('username', $this->item['username'])->first();
if ($user) {
if (! $this->updating) {
@@ -80,12 +71,6 @@ class UserImporter extends ItemImporter
$this->log('Updating User');
$user->update($this->sanitizeItemForUpdating($user));
$user->save();
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)
->update(['location_id' => $user->location_id]);
// \Log::debug('UserImporter.php Updated User ' . print_r($user, true));
return;
}
+12 -7
View File
@@ -24,13 +24,10 @@ use Illuminate\Support\Facades\Notification;
class CheckoutableListener
{
/**
* Notify the user about the checked out checkoutable and add a record to the
* checkout_requests table.
* Notify the user about the checked out checkoutable
*/
public function onCheckedOut($event)
{
/**
* When the item wasn't checked out to a user, we can't send notifications
*/
@@ -61,12 +58,14 @@ class CheckoutableListener
*/
public function onCheckedIn($event)
{
\Log::debug('onCheckedIn in the Checkoutable listener fired');
\Log::debug('checkin fired');
/**
* When the item wasn't checked out to a user, we can't send notifications
*/
if (! $event->checkedOutTo instanceof User) {
\Log::debug('checked out to not a user');
return;
}
@@ -82,14 +81,16 @@ class CheckoutableListener
$acceptance->delete();
}
}
// Use default locale
\Log::debug('checked out to a user');
if (! $event->checkedOutTo->locale) {
\Log::debug('Use default settings locale');
Notification::locale(Setting::getSettings()->locale)->send(
$this->getNotifiables($event),
$this->getCheckinNotification($event)
);
} else {
\Log::debug('Use user locale? I do not think this works as expected yet');
// \Log::debug(print_r($this->getNotifiables($event), true));
Notification::send(
$this->getNotifiables($event),
$this->getCheckinNotification($event)
@@ -150,6 +151,10 @@ class CheckoutableListener
private function getCheckinNotification($event)
{
// $model = get_class($event->checkoutable);
$notificationClass = null;
switch (get_class($event->checkoutable)) {
+1 -23
View File
@@ -22,44 +22,23 @@ use App\Models\LicenseSeat;
class LogListener
{
/**
* These onBlah methods are used by the subscribe() method further down in this file.
* This one creates an action_logs entry for the checkin
* @param CheckoutableCheckedIn $event
* @return void
*
*/
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event)
{
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date);
}
/**
* These onBlah methods are used by the subscribe() method further down in this file.
* This one creates an action_logs entry for the checkout
*
* @param CheckoutableCheckedOut $event
* @return void
*
*/
public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
{
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout);
}
/**
* These onBlah methods are used by the subscribe() method further down in this file.
* This creates the entry in the action_logs table for the accept/decline action
*/
public function onCheckoutAccepted(CheckoutAccepted $event)
{
\Log::debug('event passed to the onCheckoutAccepted listener:');
$logaction = new Actionlog();
$logaction->item()->associate($event->acceptance->checkoutable);
$logaction->target()->associate($event->acceptance->assignedTo);
$logaction->accept_signature = $event->acceptance->signature_filename;
$logaction->filename = $event->acceptance->stored_eula_file;
$logaction->action_type = 'accepted';
// TODO: log the actual license seat that was checked out
@@ -67,7 +46,6 @@ class LogListener
$logaction->item()->associate($event->acceptance->checkoutable->license);
}
\Log::debug('New onCheckoutAccepted Listener fired. logaction: '.print_r($logaction, true));
$logaction->save();
}
+3 -21
View File
@@ -37,7 +37,7 @@ class Accessory extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'model_number', 'order_number', 'purchase_date', 'notes'];
protected $searchableAttributes = ['name', 'model_number', 'order_number', 'purchase_date'];
/**
* The relations and their attributes that should be included when searching the model.
@@ -61,10 +61,9 @@ class Accessory extends SnipeModel
'category_id' => 'required|integer|exists:categories,id',
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_cost' => 'numeric|nullable',
];
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
@@ -95,7 +94,6 @@ class Accessory extends SnipeModel
'qty',
'min_amt',
'requestable',
'notes',
];
@@ -112,7 +110,6 @@ class Accessory extends SnipeModel
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id');
}
/**
* Sets the requestable attribute on the accessory
*
@@ -223,8 +220,8 @@ class Accessory extends SnipeModel
if ($this->image) {
return Storage::disk('public')->url(app('accessories_upload_path').$this->image);
}
return false;
return false;
}
/**
@@ -310,21 +307,6 @@ class Accessory extends SnipeModel
return null;
}
/**
* Check how many items within an accessory are checked out
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0]
* @return int
*/
public function numCheckedOut()
{
$checkedout = 0;
$checkedout = $this->users->count();
return $checkedout;
}
/**
* Check how many items of an accessory remain
*
+2 -6
View File
@@ -25,7 +25,7 @@ class Actionlog extends SnipeModel
protected $table = 'action_logs';
public $timestamps = true;
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type', 'stored_eula'];
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type'];
use Searchable;
@@ -34,7 +34,7 @@ class Actionlog extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['action_type', 'note', 'log_meta','user_id'];
protected $searchableAttributes = ['action_type', 'note', 'log_meta'];
/**
* The relations and their attributes that should be included when searching the model.
@@ -43,7 +43,6 @@ class Actionlog extends SnipeModel
*/
protected $searchableRelations = [
'company' => ['name'],
'user' => ['first_name','last_name','username'],
];
/**
@@ -70,7 +69,6 @@ class Actionlog extends SnipeModel
});
}
/**
* Establishes the actionlog -> item relationship
*
@@ -127,7 +125,6 @@ class Actionlog extends SnipeModel
return camel_case(class_basename($this->target_type));
}
/**
* Establishes the actionlog -> uploads relationship
*
@@ -191,7 +188,6 @@ class Actionlog extends SnipeModel
return $this->belongsTo(\App\Models\Location::class, 'location_id')->withTrashed();
}
/**
* Check if the file exists, and if it does, force a download
*
+2 -44
View File
@@ -111,7 +111,7 @@ class Asset extends Depreciable
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
'status' => 'integer',
'serial' => 'unique_serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_cost' => 'numeric|nullable',
'next_audit_date' => 'date|nullable',
'last_audit_date' => 'date|nullable',
'supplier_id' => 'exists:suppliers,id|nullable',
@@ -195,25 +195,10 @@ class Asset extends Depreciable
$model = AssetModel::find($this->model_id);
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field){
if($field->format == 'BOOLEAN'){
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
}
}
$this->rules += $model->fieldset->validation_rules();
foreach ($this->model->fieldset->fields as $field){
if($field->format == 'BOOLEAN'){
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
}
}
}
}
return parent::save($params);
}
@@ -1147,31 +1132,6 @@ class Asset extends Depreciable
}
/**
* Query builder scope for Archived assets counting
*
* This is primarily used for the tab counters so that IF the admin
* has chosen to not display archived assets in their regular lists
* and views, it will return the correct number.
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeAssetsForShow($query)
{
if (Setting::getSettings()->show_archived_in_list!=1) {
return $query->whereHas('assetstatus', function ($query) {
$query->where('archived', '=', 0);
});
} else {
return $query;
}
}
/**
* Query builder scope for Archived assets
*
@@ -1212,9 +1172,7 @@ class Asset extends Depreciable
public function scopeRequestableAssets($query)
{
$table = $query->getModel()->getTable();
return Company::scopeCompanyables($query->where($table.'.requestable', '=', 1))
return Company::scopeCompanyables($query->where('requestable', '=', 1))
->whereHas('assetstatus', function ($query) {
$query->where(function ($query) {
$query->where('deployable', '=', 1)
-14
View File
@@ -162,20 +162,6 @@ class AssetMaintenance extends Model implements ICompanyableChild
* -----------------------------------------------
**/
/**
* Query builder scope to order on a supplier
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param string $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderBySupplier($query, $order)
{
return $query->leftJoin('suppliers as suppliers_maintenances', 'asset_maintenances.supplier_id', '=', 'suppliers_maintenances.id')
->orderBy('suppliers_maintenances.name', $order);
}
/**
* Query builder scope to order on admin user
*
+1 -18
View File
@@ -20,7 +20,7 @@ class AssetModel extends SnipeModel
use HasFactory;
use SoftDeletes;
protected $presenter = \App\Presenters\AssetModelPresenter::class;
use Loggable, Requestable, Presentable;
use Requestable, Presentable;
protected $table = 'models';
protected $hidden = ['user_id', 'deleted_at'];
@@ -181,23 +181,6 @@ class AssetModel extends SnipeModel
return false;
}
/**
* Get uploads for this model
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function uploads()
{
return $this->hasMany('\App\Models\Actionlog', 'item_id')
->where('item_type', '=', AssetModel::class)
->where('action_type', '=', 'uploaded')
->whereNotNull('filename')
->orderBy('created_at', 'desc');
}
/**
* -----------------------------------------------
* BEGIN QUERY SCOPES
+3 -7
View File
@@ -57,24 +57,20 @@ class CheckoutAcceptance extends Model
}
/**
* Add a record to the checkout_acceptance table ONLY.
* Do not add stuff here that doesn't have a corresponding column in the
* checkout_acceptances table or you'll get an error.
* Accept the checkout acceptance
*
* @param string $signature_filename
*/
public function accept($signature_filename, $eula = null, $filename = null)
public function accept($signature_filename)
{
$this->accepted_at = now();
$this->signature_filename = $signature_filename;
$this->stored_eula = $eula;
$this->stored_eula_file = $filename;
$this->save();
/**
* Update state for the checked out item
*/
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename, $filename);
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename);
}
/**
+2 -3
View File
@@ -36,7 +36,7 @@ class Component extends SnipeModel
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_date' => 'date|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_cost' => 'numeric|nullable',
];
/**
@@ -65,7 +65,6 @@ class Component extends SnipeModel
'order_number',
'qty',
'serial',
'notes',
];
use Searchable;
@@ -75,7 +74,7 @@ class Component extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'order_number', 'serial', 'purchase_cost', 'purchase_date', 'notes'];
protected $searchableAttributes = ['name', 'order_number', 'serial', 'purchase_cost', 'purchase_date'];
/**
* The relations and their attributes that should be included when searching the model.

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