Merge branch 'develop' into livewire-importer-improvements
# Conflicts: # resources/views/livewire/importer.blade.php
This commit is contained in:
commit
6521c02526
1594 changed files with 28478 additions and 267672 deletions
|
@ -3145,6 +3145,42 @@
|
||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "dbakan",
|
||||||
|
"name": "Daniel Albertsen",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/4498077?v=4",
|
||||||
|
"profile": "https://ditscheri.com",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "r-xyz",
|
||||||
|
"name": "r-xyz",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/100710244?v=4",
|
||||||
|
"profile": "https://github.com/r-xyz",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "DrekiDegga",
|
||||||
|
"name": "Steven Mainor",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/47491036?v=4",
|
||||||
|
"profile": "https://github.com/DrekiDegga",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "arne-kroeger",
|
||||||
|
"name": "arne-kroeger",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/65785975?v=4",
|
||||||
|
"profile": "https://github.com/arne-kroeger",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ=
|
||||||
APP_URL=http://localhost:8000
|
APP_URL=http://localhost:8000
|
||||||
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
||||||
APP_TIMEZONE='UTC'
|
APP_TIMEZONE='UTC'
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en-US
|
||||||
MAX_RESULTS=500
|
MAX_RESULTS=500
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|
|
@ -6,7 +6,7 @@ APP_DEBUG=false
|
||||||
APP_KEY=base64:hTUIUh9CP6dQx+6EjSlfWTgbaMaaRvlpEwk45vp+xmk=
|
APP_KEY=base64:hTUIUh9CP6dQx+6EjSlfWTgbaMaaRvlpEwk45vp+xmk=
|
||||||
APP_URL=http://127.0.0.1:8000
|
APP_URL=http://127.0.0.1:8000
|
||||||
APP_TIMEZONE='US/Eastern'
|
APP_TIMEZONE='US/Eastern'
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en-US
|
||||||
APP_LOCKED=false
|
APP_LOCKED=false
|
||||||
MAX_RESULTS=200
|
MAX_RESULTS=200
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ SESSION_LIFETIME=12000
|
||||||
EXPIRE_ON_CLOSE=false
|
EXPIRE_ON_CLOSE=false
|
||||||
ENCRYPT=false
|
ENCRYPT=false
|
||||||
COOKIE_NAME=snipeit_session
|
COOKIE_NAME=snipeit_session
|
||||||
|
PASSPORT_COOKIE_NAME='snipeit_passport_token'
|
||||||
COOKIE_DOMAIN=null
|
COOKIE_DOMAIN=null
|
||||||
SECURE_COOKIES=false
|
SECURE_COOKIES=false
|
||||||
API_TOKEN_EXPIRATION_YEARS=15
|
API_TOKEN_EXPIRATION_YEARS=15
|
||||||
|
@ -183,6 +184,7 @@ REPORT_TIME_LIMIT=12000
|
||||||
REQUIRE_SAML=false
|
REQUIRE_SAML=false
|
||||||
API_THROTTLE_PER_MINUTE=120
|
API_THROTTLE_PER_MINUTE=120
|
||||||
CSV_ESCAPE_FORMULAS=true
|
CSV_ESCAPE_FORMULAS=true
|
||||||
|
LIVEWIRE_URL_PREFIX=null
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# OPTIONAL: HASHING
|
# OPTIONAL: HASHING
|
||||||
|
|
2
.github/workflows/codacy-analysis.yml
vendored
2
.github/workflows/codacy-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
|
|
||||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||||
- name: Run Codacy Analysis CLI
|
- name: Run Codacy Analysis CLI
|
||||||
uses: codacy/codacy-analysis-cli-action@v4.4.1
|
uses: codacy/codacy-analysis-cli-action@v4.4.5
|
||||||
with:
|
with:
|
||||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
# 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
|
# You can also omit the token and run the tools that support default configurations
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -67,3 +67,4 @@ _ide_helper_models.php
|
||||||
/.phplint-cache
|
/.phplint-cache
|
||||||
storage/ldap_client_tls.cert
|
storage/ldap_client_tls.cert
|
||||||
storage/ldap_client_tls.key
|
storage/ldap_client_tls.key
|
||||||
|
/storage/framework/testing
|
||||||
|
|
|
@ -51,7 +51,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [<img src="https://avatars.githubusercontent.com/u/58479551?v=4" width="110px;"/><br /><sub>Bogdan</sub>](http://@singrity)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") | [<img src="https://avatars.githubusercontent.com/u/3483684?v=4" width="110px;"/><br /><sub>mmanjos</sub>](https://github.com/mmanjos)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mmanjos "Code") | [<img src="https://avatars.githubusercontent.com/u/7429229?v=4" width="110px;"/><br /><sub>Abdelaziz Faki</sub>](https://azooz2014.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azooz2014 "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [<img src="https://avatars.githubusercontent.com/u/58479551?v=4" width="110px;"/><br /><sub>Bogdan</sub>](http://@singrity)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") | [<img src="https://avatars.githubusercontent.com/u/3483684?v=4" width="110px;"/><br /><sub>mmanjos</sub>](https://github.com/mmanjos)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mmanjos "Code") | [<img src="https://avatars.githubusercontent.com/u/7429229?v=4" width="110px;"/><br /><sub>Abdelaziz Faki</sub>](https://azooz2014.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azooz2014 "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/47315739?v=4" width="110px;"/><br /><sub>bilias</sub>](https://github.com/bilias)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/47315739?v=4" width="110px;"/><br /><sub>bilias</sub>](https://github.com/bilias)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
|
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") |
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
FROM alpine:3.18.6
|
FROM alpine:3.19
|
||||||
# Apache + PHP
|
# Apache + PHP
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
apache2 \
|
apache2 \
|
||||||
php81 \
|
php82 \
|
||||||
php81-common \
|
php82-common \
|
||||||
php81-apache2 \
|
php82-apache2 \
|
||||||
php81-curl \
|
php82-curl \
|
||||||
php81-ldap \
|
php82-ldap \
|
||||||
php81-mysqli \
|
php82-mysqli \
|
||||||
php81-gd \
|
php82-gd \
|
||||||
php81-xml \
|
php82-xml \
|
||||||
php81-mbstring \
|
php82-mbstring \
|
||||||
php81-zip \
|
php82-zip \
|
||||||
php81-ctype \
|
php82-ctype \
|
||||||
php81-tokenizer \
|
php82-tokenizer \
|
||||||
php81-pdo_mysql \
|
php82-pdo_mysql \
|
||||||
php81-openssl \
|
php82-openssl \
|
||||||
php81-bcmath \
|
php82-bcmath \
|
||||||
php81-phar \
|
php82-phar \
|
||||||
php81-json \
|
php82-json \
|
||||||
php81-iconv \
|
php82-iconv \
|
||||||
php81-fileinfo \
|
php82-fileinfo \
|
||||||
php81-simplexml \
|
php82-simplexml \
|
||||||
php81-session \
|
php82-session \
|
||||||
php81-dom \
|
php82-dom \
|
||||||
php81-xmlwriter \
|
php82-xmlwriter \
|
||||||
php81-xmlreader \
|
php82-xmlreader \
|
||||||
php81-sodium \
|
php82-sodium \
|
||||||
php81-redis \
|
php82-redis \
|
||||||
php81-pecl-memcached \
|
php82-pecl-memcached \
|
||||||
php81-exif \
|
php82-exif \
|
||||||
curl \
|
curl \
|
||||||
wget \
|
wget \
|
||||||
vim \
|
vim \
|
||||||
|
@ -42,7 +42,7 @@ COPY docker/column-statistics.cnf /etc/mysql/conf.d/column-statistics.cnf
|
||||||
# Where apache's PID lives
|
# Where apache's PID lives
|
||||||
RUN mkdir -p /run/apache2 && chown apache:apache /run/apache2
|
RUN mkdir -p /run/apache2 && chown apache:apache /run/apache2
|
||||||
|
|
||||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php81/php.ini
|
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php82/php.ini
|
||||||
COPY docker/000-default-2.4.conf /etc/apache2/conf.d/default.conf
|
COPY docker/000-default-2.4.conf /etc/apache2/conf.d/default.conf
|
||||||
|
|
||||||
# Enable mod_rewrite
|
# Enable mod_rewrite
|
||||||
|
|
|
@ -20,7 +20,7 @@ APP_DEBUG=true
|
||||||
APP_KEY=base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU=
|
APP_KEY=base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU=
|
||||||
APP_URL=http://localhost:8000
|
APP_URL=http://localhost:8000
|
||||||
APP_TIMEZONE='UTC'
|
APP_TIMEZONE='UTC'
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en-US
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
# REQUIRED: DATABASE SETTINGS
|
# REQUIRED: DATABASE SETTINGS
|
||||||
|
|
|
@ -251,6 +251,7 @@ class LdapSync extends Command
|
||||||
// Creating a new user.
|
// Creating a new user.
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->password = $user->noPassword();
|
$user->password = $user->noPassword();
|
||||||
|
$user->locale = app()->getLocale();
|
||||||
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
||||||
$item['createorupdate'] = 'created';
|
$item['createorupdate'] = 'created';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
|
@ -15,6 +16,8 @@ use App\Models\Statuslabel;
|
||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class Purge extends Command
|
class Purge extends Command
|
||||||
{
|
{
|
||||||
|
@ -141,6 +144,20 @@ class Purge extends Command
|
||||||
$this->info($users->count().' users purged.');
|
$this->info($users->count().' users purged.');
|
||||||
$user_assoc = 0;
|
$user_assoc = 0;
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
|
|
||||||
|
$rel_path = 'private_uploads/users';
|
||||||
|
$filenames = Actionlog::where('action_type', 'uploaded')
|
||||||
|
->where('item_id', $user->id)
|
||||||
|
->pluck('filename');
|
||||||
|
foreach($filenames as $filename) {
|
||||||
|
try {
|
||||||
|
if (Storage::exists($rel_path . '/' . $filename)) {
|
||||||
|
Storage::delete($rel_path . '/' . $filename);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::info('An error occurred while deleting files: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->info('- User "'.$user->username.'" deleted.');
|
$this->info('- User "'.$user->username.'" deleted.');
|
||||||
$user_assoc += $user->userlog()->count();
|
$user_assoc += $user->userlog()->count();
|
||||||
$user->userlog()->forceDelete();
|
$user->userlog()->forceDelete();
|
||||||
|
|
|
@ -73,6 +73,7 @@ class ResetDemoSettings extends Command
|
||||||
$settings->saml_forcelogin = '0';
|
$settings->saml_forcelogin = '0';
|
||||||
$settings->saml_slo = null;
|
$settings->saml_slo = null;
|
||||||
$settings->saml_custom_settings = null;
|
$settings->saml_custom_settings = null;
|
||||||
|
$settings->default_avatar = 'default.png';
|
||||||
|
|
||||||
|
|
||||||
$settings->save();
|
$settings->save();
|
||||||
|
|
|
@ -30,8 +30,11 @@ class SQLStreamer {
|
||||||
public function parse_sql(string $line): string {
|
public function parse_sql(string $line): string {
|
||||||
// take into account the 'start of line or not' setting as an instance variable?
|
// take into account the 'start of line or not' setting as an instance variable?
|
||||||
// 'continuation' lines for a permitted statement are PERMITTED.
|
// 'continuation' lines for a permitted statement are PERMITTED.
|
||||||
|
// remove *only* line-feeds & carriage-returns; helpful for regexes against lines from
|
||||||
|
// Windows dumps
|
||||||
|
$line = trim($line, "\r\n");
|
||||||
if($this->statement_is_permitted && $line[0] === ' ') {
|
if($this->statement_is_permitted && $line[0] === ' ') {
|
||||||
return $line;
|
return $line . "\n"; //re-add the newline
|
||||||
}
|
}
|
||||||
|
|
||||||
$table_regex = '`?([a-zA-Z0-9_]+)`?';
|
$table_regex = '`?([a-zA-Z0-9_]+)`?';
|
||||||
|
@ -42,8 +45,12 @@ class SQLStreamer {
|
||||||
"/^(INSERT INTO )$table_regex(.*)$/" => false,
|
"/^(INSERT INTO )$table_regex(.*)$/" => false,
|
||||||
"/^UNLOCK TABLES/" => false,
|
"/^UNLOCK TABLES/" => false,
|
||||||
// "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here?
|
// "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here?
|
||||||
"/^\\)[a-zA-Z0-9_= ]*;$/" => false
|
"/^\\)[a-zA-Z0-9_= ]*;$/" => false,
|
||||||
// ^^^^^^ that bit should *exit* the 'perimitted' black
|
// ^^^^^^ that bit should *exit* the 'permitted' block
|
||||||
|
"/^\\(.*\\)[,;]$/" => false, //older MySQL dump style with one set of values per line
|
||||||
|
/* we *could* have made the ^INSERT INTO blah VALUES$ turn on the capturing state, and closed it with
|
||||||
|
a ^(blahblah);$ but it's cleaner to not have to manage the state machine. We're just going to
|
||||||
|
assume that (blahblah), or (blahblah); are values for INSERT and are always acceptable. */
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach($allowed_statements as $statement => $statechange) {
|
foreach($allowed_statements as $statement => $statechange) {
|
||||||
|
@ -67,7 +74,7 @@ class SQLStreamer {
|
||||||
}
|
}
|
||||||
//how do we *replace* the tablename?
|
//how do we *replace* the tablename?
|
||||||
// print "RETURNING LINE: $line";
|
// print "RETURNING LINE: $line";
|
||||||
return $line;
|
return $line . "\n"; //re-add newline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// all that is not allowed is denied.
|
// all that is not allowed is denied.
|
||||||
|
@ -85,7 +92,7 @@ class SQLStreamer {
|
||||||
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
|
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
|
||||||
|
|
||||||
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
|
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
|
||||||
//can't use 'users' because the 'accessories_users' table?
|
//can't use 'users' because the 'accessories_checkout' table?
|
||||||
// can't use 'assets' because 'ver1_components_assets'
|
// can't use 'assets' because 'ver1_components_assets'
|
||||||
foreach($check_tables as $check_table => $_ignore) {
|
foreach($check_tables as $check_table => $_ignore) {
|
||||||
foreach ($parser->tablenames as $tablename => $_count) {
|
foreach ($parser->tablenames as $tablename => $_count) {
|
||||||
|
@ -164,7 +171,8 @@ class RestoreFromBackup extends Command
|
||||||
{filename : The zip file to be migrated}
|
{filename : The zip file to be migrated}
|
||||||
{--no-progress : Don\'t show a progress bar}
|
{--no-progress : Don\'t show a progress bar}
|
||||||
{--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL}
|
{--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL}
|
||||||
{--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}';
|
{--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}
|
||||||
|
{--sql-stdout-only : ONLY "Sanitize" the SQL and print it to stdout - useful for debugging - probably requires --sanitize-with-prefix= }';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
|
@ -365,6 +373,15 @@ class RestoreFromBackup extends Command
|
||||||
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're doing --sql-stdout-only, handle that now so we don't have to open pipes to mysql and all of that silliness
|
||||||
|
if ($this->option('sql-stdout-only')) {
|
||||||
|
$sql_importer = new SQLStreamer($sql_contents, STDOUT, $this->option('sanitize-with-prefix'));
|
||||||
|
$bytes_read = $sql_importer->line_aware_piping();
|
||||||
|
return $this->warn("$bytes_read total bytes read");
|
||||||
|
//TODO - it'd be nice to dump this message to STDERR so that STDOUT is just pure SQL,
|
||||||
|
// which would be good for redirecting to a file, and not having to trim the last line off of it
|
||||||
|
}
|
||||||
|
|
||||||
//how to invoke the restore?
|
//how to invoke the restore?
|
||||||
$pipes = [];
|
$pipes = [];
|
||||||
|
|
||||||
|
@ -466,6 +483,9 @@ class RestoreFromBackup extends Command
|
||||||
$ugly_file_name = $za->statIndex($file_details['index'])['name'];
|
$ugly_file_name = $za->statIndex($file_details['index'])['name'];
|
||||||
$fp = $za->getStream($ugly_file_name);
|
$fp = $za->getStream($ugly_file_name);
|
||||||
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
||||||
|
if (!is_dir($file_details['dest'])) {
|
||||||
|
mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that
|
||||||
|
}
|
||||||
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
||||||
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
|
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
|
||||||
fwrite($migrated_file, $buffer);
|
fwrite($migrated_file, $buffer);
|
||||||
|
|
105
app/Console/Commands/SendAcceptanceReminder.php
Normal file
105
app/Console/Commands/SendAcceptanceReminder.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\CheckoutAcceptance;
|
||||||
|
use App\Models\Setting;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Notifications\CheckoutAssetNotification;
|
||||||
|
use App\Notifications\CurrentInventory;
|
||||||
|
use App\Notifications\UnacceptedAssetReminderNotification;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
|
class SendAcceptanceReminder extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'snipeit:acceptance-reminder';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'This will resend users with unaccepted assets a reminder to accept or decline them.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$pending = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')
|
||||||
|
->whereHas('checkoutable', function($query) {
|
||||||
|
$query->where('archived', 0);
|
||||||
|
})
|
||||||
|
->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model', 'checkoutable.adminuser'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$unacceptedAssetGroups = $pending
|
||||||
|
->filter(function($acceptance) {
|
||||||
|
return $acceptance->checkoutable_type == 'App\Models\Asset';
|
||||||
|
})
|
||||||
|
->map(function($acceptance) {
|
||||||
|
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
|
||||||
|
})
|
||||||
|
->groupBy(function($item) {
|
||||||
|
return $item['acceptance']->assignedTo ? $item['acceptance']->assignedTo->id : '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$no_mail_address = [];
|
||||||
|
|
||||||
|
foreach($unacceptedAssetGroups as $unacceptedAssetGroup) {
|
||||||
|
$item_count = $unacceptedAssetGroup->count();
|
||||||
|
foreach ($unacceptedAssetGroup as $unacceptedAsset) {
|
||||||
|
// if ($unacceptedAsset['acceptance']->assignedTo->email == ''){
|
||||||
|
// $no_mail_address[] = $unacceptedAsset['checkoutable']->assignedTo->present()->fullName;
|
||||||
|
// }
|
||||||
|
if ($unacceptedAsset['acceptance']->assignedTo) {
|
||||||
|
|
||||||
|
if (!$unacceptedAsset['acceptance']->assignedTo->locale) {
|
||||||
|
Notification::locale(Setting::getSettings()->locale)->send(
|
||||||
|
$unacceptedAsset['acceptance']->assignedTo,
|
||||||
|
new UnacceptedAssetReminderNotification($unacceptedAsset['assetItem'], $count)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Notification::send(
|
||||||
|
$unacceptedAsset['acceptance']->assignedTo,
|
||||||
|
new UnacceptedAssetReminderNotification($unacceptedAsset, $item_count)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($no_mail_address)) {
|
||||||
|
foreach($no_mail_address as $user) {
|
||||||
|
return $user.' has no email.';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$this->info($count.' users notified.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,8 +62,9 @@ class Helper
|
||||||
'mn' => 'mn-MN', // Mongolian
|
'mn' => 'mn-MN', // Mongolian
|
||||||
'ms' => 'ms-MY', // Malay
|
'ms' => 'ms-MY', // Malay
|
||||||
'nl' => 'nl-NL', // Dutch
|
'nl' => 'nl-NL', // Dutch
|
||||||
'no' => 'no-NO', // Norwegian
|
'no' => 'nb-NO', // Norwegian Bokmål
|
||||||
'pl' => 'pl-PL', // Polish
|
'pl' => 'pl-PL', // Polish
|
||||||
|
'pt' => 'pt-PT', // Portuguese
|
||||||
'ro' => 'ro-RO', // Romanian
|
'ro' => 'ro-RO', // Romanian
|
||||||
'ru' => 'ru-RU', // Russian
|
'ru' => 'ru-RU', // Russian
|
||||||
'sk' => 'sk-SK', // Slovak
|
'sk' => 'sk-SK', // Slovak
|
||||||
|
@ -720,7 +721,7 @@ class Helper
|
||||||
{
|
{
|
||||||
$alert_threshold = \App\Models\Setting::getSettings()->alert_threshold;
|
$alert_threshold = \App\Models\Setting::getSettings()->alert_threshold;
|
||||||
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
|
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
|
||||||
$accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get();
|
$accessories = Accessory::withCount('checkouts as checkouts_count')->whereNotNull('min_amt')->get();
|
||||||
$components = Component::whereNotNull('min_amt')->get();
|
$components = Component::whereNotNull('min_amt')->get();
|
||||||
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
|
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
|
||||||
$licenses = License::where('min_amt', '>', 0)->get();
|
$licenses = License::where('min_amt', '>', 0)->get();
|
||||||
|
@ -748,7 +749,7 @@ class Helper
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($accessories as $accessory) {
|
foreach ($accessories as $accessory) {
|
||||||
$avail = $accessory->qty - $accessory->users_count;
|
$avail = $accessory->qty - $accessory->checkouts_count;
|
||||||
if ($avail < ($accessory->min_amt) + $alert_threshold) {
|
if ($avail < ($accessory->min_amt) + $alert_threshold) {
|
||||||
if ($accessory->qty > 0) {
|
if ($accessory->qty > 0) {
|
||||||
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
||||||
|
@ -913,13 +914,22 @@ class Helper
|
||||||
$rules = $class::rules();
|
$rules = $class::rules();
|
||||||
foreach ($rules as $rule_name => $rule) {
|
foreach ($rules as $rule_name => $rule) {
|
||||||
if ($rule_name == $field) {
|
if ($rule_name == $field) {
|
||||||
if (strpos($rule, 'required') === false) {
|
if (is_array($rule)) {
|
||||||
return false;
|
if (in_array('required', $rule)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return true;
|
if (strpos($rule, 'required') === false) {
|
||||||
}
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1440,7 +1450,6 @@ class Helper
|
||||||
|
|
||||||
foreach (self::$language_map as $legacy => $new) {
|
foreach (self::$language_map as $legacy => $new) {
|
||||||
if ($language_code == $legacy) {
|
if ($language_code == $legacy) {
|
||||||
Log::debug('Current language is '.$legacy.', using '.$new.' instead');
|
|
||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1451,6 +1460,7 @@ class Helper
|
||||||
|
|
||||||
public static function mapBackToLegacyLocale($new_locale = null)
|
public static function mapBackToLegacyLocale($new_locale = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (strlen($new_locale) <= 4) {
|
if (strlen($new_locale) <= 4) {
|
||||||
return $new_locale; //"new locale" apparently wasn't quite so new
|
return $new_locale; //"new locale" apparently wasn't quite so new
|
||||||
}
|
}
|
||||||
|
@ -1458,42 +1468,73 @@ class Helper
|
||||||
// This does a *reverse* search against our new language map array - given the value, find the *key* for it
|
// This does a *reverse* search against our new language map array - given the value, find the *key* for it
|
||||||
$legacy_locale = array_search($new_locale, self::$language_map);
|
$legacy_locale = array_search($new_locale, self::$language_map);
|
||||||
|
|
||||||
if($legacy_locale !== false) {
|
if ($legacy_locale !== false) {
|
||||||
return $legacy_locale;
|
return $legacy_locale;
|
||||||
}
|
}
|
||||||
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
return $new_locale; // better that you have some weird locale that doesn't fit into our mappings anywhere than 'void'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function determineLanguageDirection() {
|
||||||
|
return in_array(app()->getLocale(),
|
||||||
|
[
|
||||||
|
'ar-SA',
|
||||||
|
'fa-IR',
|
||||||
|
'he-IL'
|
||||||
|
]) ? 'rtl' : 'ltr';
|
||||||
|
}
|
||||||
|
|
||||||
static public function getRedirectOption($request, $id, $table, $asset_id = null)
|
|
||||||
|
static public function getRedirectOption($request, $id, $table, $item_id = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
$redirect_option = Session::get('redirect_option');
|
$redirect_option = Session::get('redirect_option');
|
||||||
$checkout_to_type = Session::get('checkout_to_type');
|
$checkout_to_type = Session::get('checkout_to_type');
|
||||||
|
|
||||||
//return to index
|
// return to index
|
||||||
if ($redirect_option == '0') {
|
if ($redirect_option == 'index') {
|
||||||
switch ($table) {
|
switch ($table) {
|
||||||
case "Assets":
|
case "Assets":
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
return route('hardware.index');
|
||||||
|
case "Users":
|
||||||
|
return route('users.index');
|
||||||
|
case "Licenses":
|
||||||
|
return route('licenses.index');
|
||||||
|
case "Accessories":
|
||||||
|
return route('accessories.index');
|
||||||
|
case "Components":
|
||||||
|
return route('components.index');
|
||||||
|
case "Consumables":
|
||||||
|
return route('consumables.index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//return to thing being assigned
|
|
||||||
if ($redirect_option == '1') {
|
// return to thing being assigned
|
||||||
|
if ($redirect_option == 'item') {
|
||||||
switch ($table) {
|
switch ($table) {
|
||||||
case "Assets":
|
case "Assets":
|
||||||
return redirect()->route('hardware.show', $id ? $id : $asset_id)->with('success', trans('admin/hardware/message.checkout.success'));
|
return route('hardware.show', $id ?? $item_id);
|
||||||
|
case "Users":
|
||||||
|
return route('users.show', $id ?? $item_id);
|
||||||
|
case "Licenses":
|
||||||
|
return route('licenses.show', $id ?? $item_id);
|
||||||
|
case "Accessories":
|
||||||
|
return route('accessories.show', $id ?? $item_id);
|
||||||
|
case "Components":
|
||||||
|
return route('components.show', $id ?? $item_id);
|
||||||
|
case "Consumables":
|
||||||
|
return route('consumables.show', $id ?? $item_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//return to thing being assigned to
|
|
||||||
if ($redirect_option == '2') {
|
// return to assignment target
|
||||||
|
if ($redirect_option == 'target') {
|
||||||
switch ($checkout_to_type) {
|
switch ($checkout_to_type) {
|
||||||
case 'user':
|
case 'user':
|
||||||
return redirect()->route('users.show', $request->assigned_user)->with('success', trans('admin/hardware/message.checkout.success'));
|
return route('users.show', ['user' => $request->assigned_user]);
|
||||||
case 'location':
|
case 'location':
|
||||||
return redirect()->route('locations.show', $request->assigned_location)->with('success', trans('admin/hardware/message.checkout.success'));
|
return route('locations.show', ['location' => $request->assigned_location]);
|
||||||
case 'asset':
|
case 'asset':
|
||||||
return redirect()->route('hardware.show', $request->assigned_asset)->with('success', trans('admin/hardware/message.checkout.success'));
|
return route('hardware.show', ['hardware' => $request->assigned_asset]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));
|
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'));
|
||||||
|
|
|
@ -79,10 +79,11 @@ class AccessoriesController extends Controller
|
||||||
|
|
||||||
$accessory = $request->handleImages($accessory);
|
$accessory = $request->handleImages($accessory);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
// Was the accessory created?
|
// Was the accessory created?
|
||||||
if ($accessory->save()) {
|
if ($accessory->save()) {
|
||||||
// Redirect to the new accessory page
|
// Redirect to the new accessory page
|
||||||
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.create.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
|
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
|
||||||
|
@ -143,12 +144,12 @@ class AccessoriesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse
|
public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
|
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId)) {
|
||||||
|
|
||||||
$this->authorize($accessory);
|
$this->authorize($accessory);
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
"qty" => "required|numeric|min:$accessory->users_count"
|
"qty" => "required|numeric|min:$accessory->checkouts_count"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
|
@ -176,9 +177,10 @@ class AccessoriesController extends Controller
|
||||||
|
|
||||||
$accessory = $request->handleImages($accessory);
|
$accessory = $request->handleImages($accessory);
|
||||||
|
|
||||||
// Was the accessory updated?
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($accessory->save()) {
|
if ($accessory->save()) {
|
||||||
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.update.success'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||||
|
@ -231,7 +233,7 @@ class AccessoriesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function show($accessoryID = null) : View | RedirectResponse
|
public function show($accessoryID = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
|
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryID);
|
||||||
$this->authorize('view', $accessory);
|
$this->authorize('view', $accessory);
|
||||||
if (isset($accessory->id)) {
|
if (isset($accessory->id)) {
|
||||||
return view('accessories/view', compact('accessory'));
|
return view('accessories/view', compact('accessory'));
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
namespace App\Http\Controllers\Accessories;
|
namespace App\Http\Controllers\Accessories;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\AccessoryCheckout;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
@ -23,7 +25,7 @@ class AccessoryCheckinController extends Controller
|
||||||
*/
|
*/
|
||||||
public function create($accessoryUserId = null, $backto = null) : View | RedirectResponse
|
public function create($accessoryUserId = null, $backto = null) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
if (is_null($accessory_user = DB::table('accessories_checkout')->find($accessoryUserId))) {
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,16 +40,16 @@ class AccessoryCheckinController extends Controller
|
||||||
*
|
*
|
||||||
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param null $accessoryUserId
|
* @param null $accessoryCheckoutId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $accessoryUserId = null, $backto = null) : RedirectResponse
|
public function store(Request $request, $accessoryCheckoutId = null, $backto = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryCheckoutId))) {
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessory = Accessory::find($accessory_user->accessory_id);
|
$accessory = Accessory::find($accessory_checkout->accessory_id);
|
||||||
|
|
||||||
$this->authorize('checkin', $accessory);
|
$this->authorize('checkin', $accessory);
|
||||||
|
|
||||||
|
@ -58,12 +60,12 @@ class AccessoryCheckinController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// Was the accessory updated?
|
// Was the accessory updated?
|
||||||
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
|
if ($accessory_checkout->delete()) {
|
||||||
$return_to = e($accessory_user->assigned_to);
|
event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at));
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($accessory, User::find($return_to), auth()->user(), $request->input('note'), $checkin_at));
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.checkin.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the accessory management page with error
|
// Redirect to the accessory management page with error
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));
|
||||||
|
|
|
@ -3,18 +3,24 @@
|
||||||
namespace App\Http\Controllers\Accessories;
|
namespace App\Http\Controllers\Accessories;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Http\Controllers\CheckInOutRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\AccessoryCheckoutRequest;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\AccessoryCheckout;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use \Illuminate\Contracts\View\View;
|
use \Illuminate\Contracts\View\View;
|
||||||
use \Illuminate\Http\RedirectResponse;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class AccessoryCheckoutController extends Controller
|
class AccessoryCheckoutController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
use CheckInOutRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the form to checkout an Accessory to a user.
|
* Return the form to checkout an Accessory to a user.
|
||||||
*
|
*
|
||||||
|
@ -24,7 +30,7 @@ class AccessoryCheckoutController extends Controller
|
||||||
public function create($id) : View | RedirectResponse
|
public function create($id) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($accessory = Accessory::withCount('users as users_count')->find($id)) {
|
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($id)) {
|
||||||
|
|
||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
|
||||||
|
@ -57,44 +63,38 @@ class AccessoryCheckoutController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryId
|
* @param Accessory $accessory
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, $accessoryId) : RedirectResponse
|
public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
|
||||||
// Redirect to the accessory management page with error
|
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.user_not_found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
|
||||||
if (!$user = User::find($request->input('assigned_to'))) {
|
$target = $this->determineCheckoutTarget();
|
||||||
return redirect()->route('accessories.checkout.show', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
|
|
||||||
|
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||||
|
AccessoryCheckout::create([
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'assigned_to' => $target->id,
|
||||||
|
'assigned_type' => $target::class,
|
||||||
|
'note' => $request->input('note'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
// Make sure there is at least one available to checkout
|
// Set this as user since we only allow checkout to user for this item type
|
||||||
if ($accessory->numRemaining() <= 0){
|
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
|
$request->request->add(['assigned_user' => $target->id]);
|
||||||
}
|
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
// Update the accessory data
|
|
||||||
$accessory->assigned_to = e($request->input('assigned_to'));
|
|
||||||
|
|
||||||
$accessory->users()->attach($accessory->id, [
|
|
||||||
'accessory_id' => $accessory->id,
|
|
||||||
'created_at' => Carbon::now(),
|
|
||||||
'user_id' => Auth::id(),
|
|
||||||
'assigned_to' => $request->get('assigned_to'),
|
|
||||||
'note' => $request->input('note'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
|
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
|
|
||||||
|
|
||||||
// Redirect to the new accessory page
|
// Redirect to the new accessory page
|
||||||
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))
|
||||||
|
->with('success', trans('admin/accessories/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,10 @@ namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Http\Controllers\CheckInOutRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\AccessoryCheckoutRequest;
|
||||||
|
use App\Http\Requests\StoreAccessoryRequest;
|
||||||
use App\Http\Transformers\AccessoriesTransformer;
|
use App\Http\Transformers\AccessoriesTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
@ -15,10 +18,12 @@ use Carbon\Carbon;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
use App\Models\AccessoryCheckout;
|
||||||
|
|
||||||
class AccessoriesController extends Controller
|
class AccessoriesController extends Controller
|
||||||
{
|
{
|
||||||
|
use CheckInOutRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
|
@ -46,13 +51,13 @@ class AccessoriesController extends Controller
|
||||||
'min_amt',
|
'min_amt',
|
||||||
'company_id',
|
'company_id',
|
||||||
'notes',
|
'notes',
|
||||||
'users_count',
|
'checkouts_count',
|
||||||
'qty',
|
'qty',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier')
|
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier')
|
||||||
->withCount('users as users_count');
|
->withCount('checkouts as checkouts_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$accessories = $accessories->TextSearch($request->input('search'));
|
$accessories = $accessories->TextSearch($request->input('search'));
|
||||||
|
@ -121,12 +126,12 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
|
* @param \App\Http\Requests\ImageUploadRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function store(ImageUploadRequest $request)
|
public function store(StoreAccessoryRequest $request)
|
||||||
{
|
{
|
||||||
$this->authorize('create', Accessory::class);
|
$this->authorize('create', Accessory::class);
|
||||||
$accessory = new Accessory;
|
$accessory = new Accessory;
|
||||||
|
@ -144,15 +149,15 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return array
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
$this->authorize('view', Accessory::class);
|
$this->authorize('view', Accessory::class);
|
||||||
$accessory = Accessory::withCount('users as users_count')->findOrFail($id);
|
$accessory = Accessory::withCount('checkouts as checkouts_count')->findOrFail($id);
|
||||||
|
|
||||||
return (new AccessoriesTransformer)->transformAccessory($accessory);
|
return (new AccessoriesTransformer)->transformAccessory($accessory);
|
||||||
}
|
}
|
||||||
|
@ -161,10 +166,10 @@ class AccessoriesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return array
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @param int $id
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
*/
|
||||||
public function accessory_detail($id)
|
public function accessory_detail($id)
|
||||||
{
|
{
|
||||||
|
@ -195,28 +200,23 @@ class AccessoriesController extends Controller
|
||||||
$offset = request('offset', 0);
|
$offset = request('offset', 0);
|
||||||
$limit = request('limit', 50);
|
$limit = request('limit', 50);
|
||||||
|
|
||||||
$accessory_users = $accessory->users;
|
$accessory_checkouts = $accessory->checkouts;
|
||||||
$total = $accessory_users->count();
|
$total = $accessory_checkouts->count();
|
||||||
|
|
||||||
if ($total < $offset) {
|
if ($total < $offset) {
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessory_users = $accessory->users()->skip($offset)->take($limit)->get();
|
$accessory_checkouts = $accessory->checkouts()->skip($offset)->take($limit)->get();
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$accessory_users = $accessory->users()
|
|
||||||
->where(function ($query) use ($request) {
|
$accessory_checkouts = $accessory->checkouts()->TextSearch($request->input('search'))
|
||||||
$search_str = '%' . $request->input('search') . '%';
|
|
||||||
$query->where('first_name', 'like', $search_str)
|
|
||||||
->orWhere('last_name', 'like', $search_str)
|
|
||||||
->orWhere('note', 'like', $search_str);
|
|
||||||
})
|
|
||||||
->get();
|
->get();
|
||||||
$total = $accessory_users->count();
|
$total = $accessory_checkouts->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_users, $total);
|
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_checkouts, $total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,43 +273,31 @@ class AccessoriesController extends Controller
|
||||||
* If Slack is enabled and/or asset acceptance is enabled, it will also
|
* If Slack is enabled and/or asset acceptance is enabled, it will also
|
||||||
* trigger a Slack message and send an email.
|
* trigger a Slack message and send an email.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function checkout(Request $request, $accessoryId)
|
public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory)
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
|
||||||
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
$target = $this->determineCheckoutTarget();
|
||||||
|
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
|
||||||
if ($accessory->numRemaining() > 0) {
|
AccessoryCheckout::create([
|
||||||
|
|
||||||
if (! $user = User::find($request->input('assigned_to'))) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkout.user_does_not_exist')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the accessory data
|
|
||||||
$accessory->assigned_to = $request->input('assigned_to');
|
|
||||||
|
|
||||||
$accessory->users()->attach($accessory->id, [
|
|
||||||
'accessory_id' => $accessory->id,
|
'accessory_id' => $accessory->id,
|
||||||
'created_at' => Carbon::now(),
|
'created_at' => Carbon::now(),
|
||||||
'user_id' => Auth::id(),
|
'user_id' => Auth::id(),
|
||||||
'assigned_to' => $request->get('assigned_to'),
|
'assigned_to' => $target->id,
|
||||||
'note' => $request->get('note'),
|
'assigned_type' => $target::class,
|
||||||
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'No accessories remaining'));
|
// Set this value to be able to pass the qty through to the event
|
||||||
|
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,19 +314,19 @@ class AccessoriesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $accessoryUserId = null)
|
public function checkin(Request $request, $accessoryUserId = null)
|
||||||
{
|
{
|
||||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessory = Accessory::find($accessory_user->accessory_id);
|
$accessory = Accessory::find($accessory_checkout->accessory_id);
|
||||||
$this->authorize('checkin', $accessory);
|
$this->authorize('checkin', $accessory);
|
||||||
|
|
||||||
$logaction = $accessory->logCheckin(User::find($accessory_user->assigned_to), $request->input('note'));
|
$logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
|
||||||
|
|
||||||
// Was the accessory updated?
|
// Was the accessory updated?
|
||||||
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
|
if ($accessory_checkout->delete()) {
|
||||||
if (! is_null($accessory_user->assigned_to)) {
|
if (! is_null($accessory_checkout->assigned_to)) {
|
||||||
$user = User::find($accessory_user->assigned_to);
|
$user = User::find($accessory_checkout->assigned_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['log_id'] = $logaction->id;
|
$data['log_id'] = $logaction->id;
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
use App\Http\Requests\StoreAssetRequest;
|
use App\Http\Requests\StoreAssetRequest;
|
||||||
|
use App\Http\Requests\UpdateAssetRequest;
|
||||||
use App\Http\Traits\MigratesLegacyAssetLocations;
|
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
|
@ -651,36 +652,35 @@ class AssetsController extends Controller
|
||||||
* Accepts a POST request to update an asset
|
* Accepts a POST request to update an asset
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param \App\Http\Requests\ImageUploadRequest $request
|
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $id) : JsonResponse
|
public function update(UpdateAssetRequest $request, Asset $asset): JsonResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$asset->fill($request->validated());
|
||||||
|
|
||||||
if ($asset = Asset::find($id)) {
|
if ($request->has('model_id')) {
|
||||||
$asset->fill($request->all());
|
$asset->model()->associate(AssetModel::find($request->validated()['model_id']));
|
||||||
|
}
|
||||||
|
if ($request->has('company_id')) {
|
||||||
|
$asset->company_id = Company::getIdForCurrentUser($request->validated()['company_id']);
|
||||||
|
}
|
||||||
|
if ($request->has('rtd_location_id') && !$request->has('location_id')) {
|
||||||
|
$asset->location_id = $request->validated()['rtd_location_id'];
|
||||||
|
}
|
||||||
|
if ($request->input('last_audit_date')) {
|
||||||
|
$asset->last_audit_date = Carbon::parse($request->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
($request->filled('model_id')) ?
|
/**
|
||||||
$asset->model()->associate(AssetModel::find($request->get('model_id'))) : null;
|
* this is here just legacy reasons. Api\AssetController
|
||||||
($request->filled('rtd_location_id')) ?
|
* used image_source once to allow encoded image uploads.
|
||||||
$asset->location_id = $request->get('rtd_location_id') : '';
|
*/
|
||||||
($request->filled('company_id')) ?
|
if ($request->has('image_source')) {
|
||||||
$asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : '';
|
$request->offsetSet('image', $request->offsetGet('image_source'));
|
||||||
|
}
|
||||||
|
|
||||||
($request->filled('rtd_location_id')) ?
|
$asset = $request->handleImages($asset);
|
||||||
$asset->location_id = $request->get('rtd_location_id') : null;
|
$model = $asset->model;
|
||||||
|
|
||||||
/**
|
|
||||||
* this is here just legacy reasons. Api\AssetController
|
|
||||||
* used image_source once to allow encoded image uploads.
|
|
||||||
*/
|
|
||||||
if ($request->has('image_source')) {
|
|
||||||
$request->offsetSet('image', $request->offsetGet('image_source'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$asset = $request->handleImages($asset);
|
|
||||||
$model = AssetModel::find($asset->model_id);
|
|
||||||
|
|
||||||
// Update custom fields
|
// Update custom fields
|
||||||
$problems_updating_encrypted_custom_fields = false;
|
$problems_updating_encrypted_custom_fields = false;
|
||||||
|
@ -706,15 +706,13 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
|
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
|
||||||
$location = $target->location_id;
|
$location = $target->location_id;
|
||||||
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) {
|
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) {
|
||||||
$location = $target->location_id;
|
$location = $target->location_id;
|
||||||
|
|
||||||
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $id)
|
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $asset->id)
|
||||||
->update(['location_id' => $target->location_id]);
|
->update(['location_id' => $target->location_id]);
|
||||||
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
|
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
|
||||||
$location = $target->id;
|
$location = $target->id;
|
||||||
|
@ -728,17 +726,13 @@ class AssetsController extends Controller
|
||||||
$asset->image = $asset->getImageUrl();
|
$asset->image = $asset->getImageUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($problems_updating_encrypted_custom_fields) {
|
if ($problems_updating_encrypted_custom_fields) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||||
} else {
|
} else {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
|
||||||
}
|
}
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class LicensesController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('view', License::class);
|
$this->authorize('view', License::class);
|
||||||
|
|
||||||
$licenses = License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count');
|
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
|
||||||
|
|
||||||
if ($request->filled('company_id')) {
|
if ($request->filled('company_id')) {
|
||||||
$licenses->where('company_id', '=', $request->input('company_id'));
|
$licenses->where('company_id', '=', $request->input('company_id'));
|
||||||
|
@ -70,6 +70,9 @@ class LicensesController extends Controller
|
||||||
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
|
$licenses->where('depreciation_id', '=', $request->input('depreciation_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('user_id')) {
|
||||||
|
$licenses->where('user_id', '=', $request->input('user_id'));
|
||||||
|
}
|
||||||
|
|
||||||
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
|
if (($request->filled('maintained')) && ($request->input('maintained')=='true')) {
|
||||||
$licenses->where('maintained','=',1);
|
$licenses->where('maintained','=',1);
|
||||||
|
@ -113,6 +116,9 @@ class LicensesController extends Controller
|
||||||
case 'company':
|
case 'company':
|
||||||
$licenses = $licenses->leftJoin('companies', 'licenses.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
|
$licenses = $licenses->leftJoin('companies', 'licenses.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
|
||||||
break;
|
break;
|
||||||
|
case 'created_by':
|
||||||
|
$licenses = $licenses->OrderCreatedBy($order);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$allowed_columns =
|
$allowed_columns =
|
||||||
[
|
[
|
||||||
|
|
|
@ -5,8 +5,10 @@ namespace App\Http\Controllers\Api;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Transformers\AssetsTransformer;
|
||||||
use App\Http\Transformers\LocationsTransformer;
|
use App\Http\Transformers\LocationsTransformer;
|
||||||
use App\Http\Transformers\SelectlistTransformer;
|
use App\Http\Transformers\SelectlistTransformer;
|
||||||
|
use App\Models\Asset;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
@ -222,6 +224,15 @@ class LocationsController extends Controller
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function assets(Request $request, Location $location) : JsonResponse | array
|
||||||
|
{
|
||||||
|
$this->authorize('view', Asset::class);
|
||||||
|
$this->authorize('view', $location);
|
||||||
|
$assets = Asset::where('assigned_to', '=', $location->id)->where('assigned_type', '=', Location::class)->with('model', 'model.category', 'assetstatus', 'location', 'company', 'defaultLoc');
|
||||||
|
$assets = $assets->get();
|
||||||
|
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
|
@ -237,6 +248,7 @@ class LocationsController extends Controller
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count')
|
->withCount('users as users_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
->findOrFail($id);
|
->findOrFail($id);
|
||||||
|
|
||||||
if (! $location->isDeletable()) {
|
if (! $location->isDeletable()) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ use App\Models\Asset;
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use \Illuminate\Contracts\View\View;
|
use \Illuminate\Contracts\View\View;
|
||||||
use \Illuminate\Http\RedirectResponse;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
|
@ -83,7 +82,6 @@ class AssetCheckinController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$asset->expected_checkin = null;
|
$asset->expected_checkin = null;
|
||||||
//$asset->last_checkout = null;
|
|
||||||
$asset->last_checkin = now();
|
$asset->last_checkin = now();
|
||||||
$asset->assignedTo()->disassociate($asset);
|
$asset->assignedTo()->disassociate($asset);
|
||||||
$asset->accepted = null;
|
$asset->accepted = null;
|
||||||
|
@ -128,12 +126,12 @@ class AssetCheckinController extends Controller
|
||||||
$acceptance->delete();
|
$acceptance->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
Session::put('redirect_option', $request->get('redirect_option'));
|
session()->put('redirect_option', $request->get('redirect_option'));
|
||||||
// Was the asset updated?
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
return Helper::getRedirectOption($asset, $assetId, 'Assets');
|
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))->with('success', trans('admin/hardware/message.checkin.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors());
|
||||||
|
|
|
@ -109,10 +109,11 @@ class AssetCheckoutController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
||||||
return Helper::getRedirectOption($request, $assetId, 'Assets');
|
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||||
|
->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
}
|
}
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
|
||||||
|
|
|
@ -204,9 +204,13 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
return redirect()->route('hardware.index')
|
|
||||||
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||||
|
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', ['hardware' => $asset->id]), 'id', 'tag' => e($asset->asset_tag)]));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -289,6 +293,7 @@ class AssetsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(ImageUploadRequest $request, $assetId = null) : RedirectResponse
|
public function update(ImageUploadRequest $request, $assetId = null) : RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
// Redirect to the asset management page with error
|
// Redirect to the asset management page with error
|
||||||
|
@ -331,7 +336,7 @@ class AssetsController extends Controller
|
||||||
|
|
||||||
$status = Statuslabel::find($asset->status_id);
|
$status = Statuslabel::find($asset->status_id);
|
||||||
|
|
||||||
if($status->archived){
|
if ($status && $status->archived) {
|
||||||
$asset->assigned_to = null;
|
$asset->assigned_to = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,14 +355,26 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the asset data
|
// Update the asset data
|
||||||
$asset_tag = $request->input('asset_tags');
|
|
||||||
$serial = $request->input('serials');
|
$serial = $request->input('serials');
|
||||||
|
$asset->serial = $request->input('serials');
|
||||||
|
|
||||||
|
if (is_array($request->input('serials'))) {
|
||||||
|
$asset->serial = $serial[1];
|
||||||
|
}
|
||||||
|
|
||||||
$asset->name = $request->input('name');
|
$asset->name = $request->input('name');
|
||||||
$asset->serial = $serial[1];
|
|
||||||
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||||
$asset->model_id = $request->input('model_id');
|
$asset->model_id = $request->input('model_id');
|
||||||
$asset->order_number = $request->input('order_number');
|
$asset->order_number = $request->input('order_number');
|
||||||
$asset->asset_tag = $asset_tag[1];
|
|
||||||
|
$asset_tags = $request->input('asset_tags');
|
||||||
|
$asset->asset_tag = $request->input('asset_tags');
|
||||||
|
|
||||||
|
if (is_array($request->input('asset_tags'))) {
|
||||||
|
$asset->asset_tag = $asset_tags[1];
|
||||||
|
}
|
||||||
|
|
||||||
$asset->notes = $request->input('notes');
|
$asset->notes = $request->input('notes');
|
||||||
|
|
||||||
$asset = $request->handleImages($asset);
|
$asset = $request->handleImages($asset);
|
||||||
|
@ -369,6 +386,7 @@ class AssetsController extends Controller
|
||||||
$model = AssetModel::find($request->get('model_id'));
|
$model = AssetModel::find($request->get('model_id'));
|
||||||
if (($model) && ($model->fieldset)) {
|
if (($model) && ($model->fieldset)) {
|
||||||
foreach ($model->fieldset->fields as $field) {
|
foreach ($model->fieldset->fields as $field) {
|
||||||
|
|
||||||
if ($field->field_encrypted == '1') {
|
if ($field->field_encrypted == '1') {
|
||||||
if (Gate::allows('admin')) {
|
if (Gate::allows('admin')) {
|
||||||
if (is_array($request->input($field->db_column))) {
|
if (is_array($request->input($field->db_column))) {
|
||||||
|
@ -387,9 +405,10 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
return redirect()->route('hardware.show', $assetId)
|
return redirect()->to(Helper::getRedirectOption($request, $assetId, 'Assets'))
|
||||||
->with('success', trans('admin/hardware/message.update.success'));
|
->with('success', trans('admin/hardware/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,9 +478,16 @@ class AssetsController extends Controller
|
||||||
$tag = $tag ? $tag : $request->get('assetTag');
|
$tag = $tag ? $tag : $request->get('assetTag');
|
||||||
$topsearch = ($request->get('topsearch') == 'true');
|
$topsearch = ($request->get('topsearch') == 'true');
|
||||||
|
|
||||||
if (! $asset = Asset::where('asset_tag', '=', $tag)->first()) {
|
// Search for an exact and unique asset tag match
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
$assets = Asset::where('asset_tag', '=', $tag);
|
||||||
|
|
||||||
|
// If not a unique result, redirect to the index view
|
||||||
|
if ($assets->count() != 1) {
|
||||||
|
return redirect()->route('hardware.index')
|
||||||
|
->with('search', $tag)
|
||||||
|
->with('warning', trans('admin/hardware/message.does_not_exist_var', [ 'asset_tag' => $tag ]));
|
||||||
}
|
}
|
||||||
|
$asset = $assets->first();
|
||||||
$this->authorize('view', $asset);
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
|
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
|
||||||
|
@ -475,7 +501,7 @@ class AssetsController extends Controller
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
*/
|
*/
|
||||||
public function getQrCode($assetId = null) : Response | BinaryFileResponse
|
public function getQrCode($assetId = null) : Response | BinaryFileResponse | string | bool
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
|
||||||
|
@ -502,6 +528,7 @@ class AssetsController extends Controller
|
||||||
|
|
||||||
return 'That asset is invalid';
|
return 'That asset is invalid';
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -575,26 +602,20 @@ class AssetsController extends Controller
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getClone($assetId = null)
|
public function getClone(Asset $asset)
|
||||||
{
|
{
|
||||||
// Check if the asset exists
|
$this->authorize('create', $asset);
|
||||||
if (is_null($asset_to_clone = Asset::find($assetId))) {
|
$cloned = clone $asset;
|
||||||
// Redirect to the asset management page
|
$cloned->id = null;
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
$cloned->asset_tag = '';
|
||||||
}
|
$cloned->serial = '';
|
||||||
|
$cloned->assigned_to = '';
|
||||||
$this->authorize('create', $asset_to_clone);
|
$cloned->deleted_at = '';
|
||||||
|
|
||||||
$asset = clone $asset_to_clone;
|
|
||||||
$asset->id = null;
|
|
||||||
$asset->asset_tag = '';
|
|
||||||
$asset->serial = '';
|
|
||||||
$asset->assigned_to = '';
|
|
||||||
|
|
||||||
return view('hardware/edit')
|
return view('hardware/edit')
|
||||||
->with('statuslabel_list', Helper::statusLabelList())
|
->with('statuslabel_list', Helper::statusLabelList())
|
||||||
->with('statuslabel_types', Helper::statusTypeList())
|
->with('statuslabel_types', Helper::statusTypeList())
|
||||||
->with('item', $asset);
|
->with('item', $cloned);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -92,7 +92,9 @@ class BulkAssetsController extends Controller
|
||||||
// This handles all of the pivot sorting below (versus the assets.* fields in the allowed_columns array)
|
// This handles all of the pivot sorting below (versus the assets.* fields in the allowed_columns array)
|
||||||
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.id';
|
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.id';
|
||||||
|
|
||||||
$assets = Asset::with('assignedTo', 'location', 'model')->whereIn('assets.id', $asset_ids);
|
$assets = Asset::with('assignedTo', 'location', 'model')
|
||||||
|
->whereIn('assets.id', $asset_ids)
|
||||||
|
->withTrashed();
|
||||||
|
|
||||||
$assets = $assets->get();
|
$assets = $assets->get();
|
||||||
|
|
||||||
|
@ -483,12 +485,7 @@ class BulkAssetsController extends Controller
|
||||||
if ($request->filled('ids')) {
|
if ($request->filled('ids')) {
|
||||||
$assets = Asset::find($request->get('ids'));
|
$assets = Asset::find($request->get('ids'));
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
$update_array['deleted_at'] = date('Y-m-d H:i:s');
|
$asset->delete();
|
||||||
$update_array['assigned_to'] = null;
|
|
||||||
|
|
||||||
DB::table('assets')
|
|
||||||
->where('id', $asset->id)
|
|
||||||
->update($update_array);
|
|
||||||
} // endforeach
|
} // endforeach
|
||||||
|
|
||||||
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
|
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
|
||||||
|
|
|
@ -87,7 +87,7 @@ class ResetPasswordController extends Controller
|
||||||
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
|
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
|
$request->validate($this->rules());
|
||||||
|
|
||||||
Log::debug('Checking if '.$request->input('username').' exists');
|
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
|
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
|
||||||
|
|
|
@ -20,7 +20,7 @@ trait CheckInOutRequest
|
||||||
return Location::findOrFail(request('assigned_location'));
|
return Location::findOrFail(request('assigned_location'));
|
||||||
case 'asset':
|
case 'asset':
|
||||||
return Asset::findOrFail(request('assigned_asset'));
|
return Asset::findOrFail(request('assigned_asset'));
|
||||||
case 'user':
|
default:
|
||||||
return User::findOrFail(request('assigned_user'));
|
return User::findOrFail(request('assigned_user'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Http\Controllers\Components;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
use App\Events\ComponentCheckedIn;
|
use App\Events\ComponentCheckedIn;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
|
@ -96,12 +97,10 @@ class ComponentCheckinController extends Controller
|
||||||
$asset = Asset::find($component_assets->asset_id);
|
$asset = Asset::find($component_assets->asset_id);
|
||||||
|
|
||||||
event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
|
event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
|
||||||
if ($backto == 'asset'){
|
|
||||||
return redirect()->route('hardware.show', $asset->id)->with('success',
|
|
||||||
trans('admin/components/message.checkin.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('components.index')->with('success',
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
|
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success',
|
||||||
trans('admin/components/message.checkin.success'));
|
trans('admin/components/message.checkin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,11 @@ namespace App\Http\Controllers\Components;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Events\ComponentCheckedOut;
|
use App\Events\ComponentCheckedOut;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
|
use App\Models\Setting;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
|
@ -93,14 +95,18 @@ class ComponentCheckoutController extends Controller
|
||||||
->withInput();
|
->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the asset exists
|
||||||
$asset = Asset::find($request->input('asset_id'));
|
$asset = Asset::find($request->input('asset_id'));
|
||||||
|
|
||||||
|
if ((Setting::getSettings()->full_multiple_companies_support) && $component->company_id !== $asset->company_id) {
|
||||||
|
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
|
||||||
|
}
|
||||||
|
|
||||||
// Update the component data
|
// Update the component data
|
||||||
$component->asset_id = $request->input('asset_id');
|
$component->asset_id = $request->input('asset_id');
|
||||||
$component->assets()->attach($component->id, [
|
$component->assets()->attach($component->id, [
|
||||||
'component_id' => $component->id,
|
'component_id' => $component->id,
|
||||||
'user_id' => auth()->user(),
|
'user_id' => auth()->user()->id,
|
||||||
'created_at' => date('Y-m-d H:i:s'),
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
'assigned_qty' => $request->input('assigned_qty'),
|
'assigned_qty' => $request->input('assigned_qty'),
|
||||||
'asset_id' => $request->input('asset_id'),
|
'asset_id' => $request->input('asset_id'),
|
||||||
|
@ -109,6 +115,11 @@ class ComponentCheckoutController extends Controller
|
||||||
|
|
||||||
event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
$request->request->add(['checkout_to_type' => 'asset']);
|
||||||
|
$request->request->add(['assigned_asset' => $asset->id]);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
|
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,8 +86,10 @@ class ComponentsController extends Controller
|
||||||
|
|
||||||
$component = $request->handleImages($component);
|
$component = $request->handleImages($component);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($component->save()) {
|
if ($component->save()) {
|
||||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
||||||
|
@ -160,8 +162,10 @@ class ComponentsController extends Controller
|
||||||
|
|
||||||
$component = $request->handleImages($component);
|
$component = $request->handleImages($component);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($component->save()) {
|
if ($component->save()) {
|
||||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
return redirect()->back()->withInput()->withErrors($component->getErrors());
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Http\Controllers\Consumables;
|
namespace App\Http\Controllers\Consumables;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
@ -33,7 +34,7 @@ class ConsumableCheckoutController extends Controller
|
||||||
// Make sure there is at least one available to checkout
|
// Make sure there is at least one available to checkout
|
||||||
if ($consumable->numRemaining() <= 0){
|
if ($consumable->numRemaining() <= 0){
|
||||||
return redirect()->route('consumables.index')
|
return redirect()->route('consumables.index')
|
||||||
->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
->with('error', trans('admin/consumables/message.checkout.unavailable', ['requested' => 1, 'remaining' => $consumable->numRemaining()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the checkout view
|
// Return the checkout view
|
||||||
|
@ -76,7 +77,7 @@ class ConsumableCheckoutController extends Controller
|
||||||
|
|
||||||
// Make sure there is at least one available to checkout
|
// Make sure there is at least one available to checkout
|
||||||
if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) {
|
if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) {
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable', ['requested' => $quantity, 'remaining' => $consumable->numRemaining() ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$admin_user = auth()->user();
|
$admin_user = auth()->user();
|
||||||
|
@ -101,7 +102,13 @@ class ConsumableCheckoutController extends Controller
|
||||||
}
|
}
|
||||||
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
|
$request->request->add(['checkout_to_type' => 'user']);
|
||||||
|
$request->request->add(['assigned_user' => $user->id]);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||||
|
|
||||||
|
|
||||||
// Redirect to the new consumable page
|
// Redirect to the new consumable page
|
||||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.checkout.success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,8 +87,10 @@ class ConsumablesController extends Controller
|
||||||
|
|
||||||
$consumable = $request->handleImages($consumable);
|
$consumable = $request->handleImages($consumable);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($consumable->save()) {
|
if ($consumable->save()) {
|
||||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.create.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
||||||
|
@ -160,8 +162,10 @@ class ConsumablesController extends Controller
|
||||||
|
|
||||||
$consumable = $request->handleImages($consumable);
|
$consumable = $request->handleImages($consumable);
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($consumable->save()) {
|
if ($consumable->save()) {
|
||||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.update.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.update.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
|
||||||
|
@ -200,7 +204,7 @@ class ConsumablesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function show($consumableId = null)
|
public function show($consumableId = null)
|
||||||
{
|
{
|
||||||
$consumable = Consumable::find($consumableId);
|
$consumable = Consumable::withCount('users as users_consumables')->find($consumableId);
|
||||||
$this->authorize($consumable);
|
$this->authorize($consumable);
|
||||||
if (isset($consumable->id)) {
|
if (isset($consumable->id)) {
|
||||||
return view('consumables/view', compact('consumable'));
|
return view('consumables/view', compact('consumable'));
|
||||||
|
@ -209,4 +213,16 @@ class ConsumablesController extends Controller
|
||||||
return redirect()->route('consumables.index')
|
return redirect()->route('consumables.index')
|
||||||
->with('error', trans('admin/consumables/message.does_not_exist'));
|
->with('error', trans('admin/consumables/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function clone(Consumable $consumable) : View
|
||||||
|
{
|
||||||
|
$this->authorize('create', $consumable);
|
||||||
|
$consumable_to_close = $consumable;
|
||||||
|
$consumable = clone $consumable_to_close;
|
||||||
|
$consumable->id = null;
|
||||||
|
$consumable->image = null;
|
||||||
|
$consumable->user_id = null;
|
||||||
|
|
||||||
|
return view('consumables/edit')->with('item', $consumable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ class CustomFieldsetsController extends Controller
|
||||||
return redirect()->route('fieldsets.show', [$id])->with('success', trans('admin/custom_fields/message.field.create.assoc_success'));
|
return redirect()->route('fieldsets.show', [$id])->with('success', trans('admin/custom_fields/message.field.create.assoc_success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('fieldsets.show', [$id])->with('error', 'No field selected.');
|
return redirect()->route('fieldsets.show', [$id])->with('error', trans('admin/custom_fields/message.field.none_selected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Http\Controllers\Licenses;
|
namespace App\Http\Controllers\Licenses;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
|
@ -100,15 +101,15 @@ class LicenseCheckinController extends Controller
|
||||||
$licenseSeat->asset_id = null;
|
$licenseSeat->asset_id = null;
|
||||||
$licenseSeat->notes = $request->input('notes');
|
$licenseSeat->notes = $request->input('notes');
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
|
|
||||||
// Was the asset updated?
|
// Was the asset updated?
|
||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
||||||
|
|
||||||
if ($backTo == 'user') {
|
|
||||||
return redirect()->route('users.show', $return_to->id)->with('success', trans('admin/licenses/message.checkin.success'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('licenses.show', $licenseSeat->license_id)->with('success', trans('admin/licenses/message.checkin.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkin.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the license page with error
|
// Redirect to the license page with error
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Http\Controllers\Licenses;
|
namespace App\Http\Controllers\Licenses;
|
||||||
|
|
||||||
use App\Events\CheckoutableCheckedOut;
|
use App\Events\CheckoutableCheckedOut;
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\LicenseCheckoutRequest;
|
use App\Http\Requests\LicenseCheckoutRequest;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
@ -81,10 +82,27 @@ class LicenseCheckoutController extends Controller
|
||||||
|
|
||||||
|
|
||||||
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
||||||
if ($this->$checkoutMethod($licenseSeat)) {
|
|
||||||
return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.checkout.success'));
|
if ($request->filled('asset_id')) {
|
||||||
|
|
||||||
|
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
|
||||||
|
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
|
||||||
|
|
||||||
|
} elseif ($request->filled('assigned_to')) {
|
||||||
|
$checkoutTarget = $this->checkoutToUser($licenseSeat);
|
||||||
|
$request->request->add(['assigned_user' => $checkoutTarget->id]);
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($checkoutTarget) {
|
||||||
|
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkout.success'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return redirect()->route('licenses.index')->with('error', trans('Something went wrong handling this checkout.'));
|
return redirect()->route('licenses.index')->with('error', trans('Something went wrong handling this checkout.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,14 +112,14 @@ class LicenseCheckoutController extends Controller
|
||||||
|
|
||||||
if (! $licenseSeat) {
|
if (! $licenseSeat) {
|
||||||
if ($seatId) {
|
if ($seatId) {
|
||||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', 'This Seat is not available for checkout.'));
|
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.unavailable')));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', 'There are no available seats for this license.'));
|
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $licenseSeat->license->is($license)) {
|
if (! $licenseSeat->license->is($license)) {
|
||||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', 'The license seat provided does not match the license.'));
|
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $licenseSeat;
|
return $licenseSeat;
|
||||||
|
@ -120,8 +138,7 @@ class LicenseCheckoutController extends Controller
|
||||||
}
|
}
|
||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
|
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
|
||||||
|
return $target;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -137,8 +154,7 @@ class LicenseCheckoutController extends Controller
|
||||||
|
|
||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
|
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
|
||||||
|
return $target;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -102,8 +102,10 @@ class LicensesController extends Controller
|
||||||
$license->user_id = Auth::id();
|
$license->user_id = Auth::id();
|
||||||
$license->min_amt = $request->input('min_amt');
|
$license->min_amt = $request->input('min_amt');
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($license->save()) {
|
if ($license->save()) {
|
||||||
return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.create.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
||||||
|
@ -180,8 +182,10 @@ class LicensesController extends Controller
|
||||||
$license->category_id = $request->input('category_id');
|
$license->category_id = $request->input('category_id');
|
||||||
$license->min_amt = $request->input('min_amt');
|
$license->min_amt = $request->input('min_amt');
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($license->save()) {
|
if ($license->save()) {
|
||||||
return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success'));
|
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.update.success'));
|
||||||
}
|
}
|
||||||
// If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php
|
// If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php
|
||||||
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
return redirect()->back()->withInput()->withErrors($license->getErrors());
|
||||||
|
|
|
@ -378,7 +378,7 @@ class ReportsController extends Controller
|
||||||
|
|
||||||
|
|
||||||
$csv = implode("\n", $rows);
|
$csv = implode("\n", $rows);
|
||||||
$response = Response::make($csv, 200);
|
$response = response()->make($csv, 200);
|
||||||
$response->header('Content-Type', 'text/csv');
|
$response->header('Content-Type', 'text/csv');
|
||||||
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
||||||
|
|
||||||
|
@ -1069,7 +1069,7 @@ class ReportsController extends Controller
|
||||||
|
|
||||||
// spit out a csv
|
// spit out a csv
|
||||||
$csv = implode("\n", $rows);
|
$csv = implode("\n", $rows);
|
||||||
$response = Response::make($csv, 200);
|
$response = response()->make($csv, 200);
|
||||||
$response->header('Content-Type', 'text/csv');
|
$response->header('Content-Type', 'text/csv');
|
||||||
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
||||||
|
|
||||||
|
@ -1249,7 +1249,7 @@ class ReportsController extends Controller
|
||||||
|
|
||||||
// spit out a csv
|
// spit out a csv
|
||||||
$csv = implode("\n", $rows);
|
$csv = implode("\n", $rows);
|
||||||
$response = Response::make($csv, 200);
|
$response = response()->make($csv, 200);
|
||||||
$response->header('Content-Type', 'text/csv');
|
$response->header('Content-Type', 'text/csv');
|
||||||
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
$response->header('Content-disposition', 'attachment;filename=report.csv');
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use App\Models\Asset;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\FirstAdminNotification;
|
use App\Notifications\FirstAdminNotification;
|
||||||
use App\Notifications\MailTest;
|
use App\Notifications\MailTest;
|
||||||
use Illuminate\Http\Client\HttpClientException;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
@ -129,11 +128,11 @@ class SettingsController extends Controller
|
||||||
protected function dotEnvFileIsExposed() : bool
|
protected function dotEnvFileIsExposed() : bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Http::timeout(10)
|
return Http::withoutVerifying()->timeout(10)
|
||||||
->accept('*/*')
|
->accept('*/*')
|
||||||
->get(URL::to('.env'))
|
->get(URL::to('.env'))
|
||||||
->successful();
|
->successful();
|
||||||
} catch (HttpClientException $e) {
|
} catch (\Exception $e) {
|
||||||
Log::debug($e->getMessage());
|
Log::debug($e->getMessage());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -325,6 +324,7 @@ class SettingsController extends Controller
|
||||||
|
|
||||||
$setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0');
|
$setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0');
|
||||||
$setting->unique_serial = $request->input('unique_serial', '0');
|
$setting->unique_serial = $request->input('unique_serial', '0');
|
||||||
|
$setting->shortcuts_enabled = $request->input('shortcuts_enabled', '0');
|
||||||
$setting->show_images_in_email = $request->input('show_images_in_email', '0');
|
$setting->show_images_in_email = $request->input('show_images_in_email', '0');
|
||||||
$setting->show_archived_in_list = $request->input('show_archived_in_list', '0');
|
$setting->show_archived_in_list = $request->input('show_archived_in_list', '0');
|
||||||
$setting->dashboard_message = $request->input('dashboard_message');
|
$setting->dashboard_message = $request->input('dashboard_message');
|
||||||
|
@ -414,10 +414,7 @@ class SettingsController extends Controller
|
||||||
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
||||||
|
|
||||||
if ($request->input('clear_logo') == '1') {
|
if ($request->input('clear_logo') == '1') {
|
||||||
|
$setting = $request->deleteExistingImage($setting, '', 'logo');
|
||||||
if (($setting->logo) && (Storage::exists($setting->logo))) {
|
|
||||||
Storage::disk('public')->delete($setting->logo);
|
|
||||||
}
|
|
||||||
$setting->logo = null;
|
$setting->logo = null;
|
||||||
$setting->brand = 1;
|
$setting->brand = 1;
|
||||||
}
|
}
|
||||||
|
@ -425,43 +422,38 @@ class SettingsController extends Controller
|
||||||
// Email logo upload
|
// Email logo upload
|
||||||
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
|
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
|
||||||
if ($request->input('clear_email_logo') == '1') {
|
if ($request->input('clear_email_logo') == '1') {
|
||||||
|
$setting = $request->deleteExistingImage($setting, '', 'email_logo');
|
||||||
if (($setting->email_logo) && (Storage::exists($setting->email_logo))) {
|
|
||||||
Storage::disk('public')->delete($setting->email_logo);
|
|
||||||
}
|
|
||||||
$setting->email_logo = null;
|
$setting->email_logo = null;
|
||||||
// If they are uploading an image, validate it and upload it
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label logo upload
|
// Label logo upload
|
||||||
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
||||||
if ($request->input('clear_label_logo') == '1') {
|
|
||||||
|
|
||||||
if (($setting->label_logo) && (Storage::exists($setting->label_logo))) {
|
if ($request->input('clear_label_logo') == '1') {
|
||||||
Storage::disk('public')->delete($setting->label_logo);
|
$setting = $request->deleteExistingImage($setting, '', 'label_logo');
|
||||||
}
|
|
||||||
$setting->label_logo = null;
|
$setting->label_logo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Favicon upload
|
// Favicon upload
|
||||||
$setting = $request->handleImages($setting, 100, 'favicon', '', 'favicon');
|
$setting = $request->handleImages($setting, 100, 'favicon', '', 'favicon');
|
||||||
if ('1' == $request->input('clear_favicon')) {
|
if ('1' == $request->input('clear_favicon')) {
|
||||||
|
$setting = $request->deleteExistingImage($setting, '', 'favicon');
|
||||||
if (($setting->favicon) && (Storage::exists($setting->favicon))) {
|
|
||||||
Storage::disk('public')->delete($setting->favicon);
|
|
||||||
}
|
|
||||||
$setting->favicon = null;
|
$setting->favicon = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default avatar upload
|
// Default avatar upload
|
||||||
$setting = $request->handleImages($setting, 500, 'default_avatar', 'avatars', 'default_avatar');
|
$setting = $request->handleImages($setting, 500, 'default_avatar', 'avatars', 'default_avatar');
|
||||||
if ($request->input('clear_default_avatar') == '1') {
|
if ($request->input('clear_default_avatar') == '1') {
|
||||||
|
// Don't delete the file, just update the field if this is the default
|
||||||
if (($setting->default_avatar) && (Storage::exists('avatars/'.$setting->default_avatar))) {
|
if ($setting->default_avatar!='default.png') {
|
||||||
Storage::disk('public')->delete('avatars/'.$setting->default_avatar);
|
$setting = $request->deleteExistingImage($setting, 'avatars', 'default_avatar');
|
||||||
}
|
}
|
||||||
$setting->default_avatar = null;
|
$setting->default_avatar = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->input('restore_default_avatar') == '1') {
|
||||||
|
$setting->default_avatar = 'default.png';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($setting->save()) {
|
if ($setting->save()) {
|
||||||
|
@ -1264,7 +1256,7 @@ class SettingsController extends Controller
|
||||||
DB::table('users')->update(['remember_token' => null]);
|
DB::table('users')->update(['remember_token' => null]);
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
|
|
||||||
return redirect()->route('login')->with('success', 'Your system has been restored. Please login again.');
|
return redirect()->route('login')->with('success', trans('admin/settings/message.restore.success'));
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
|
return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,8 +218,8 @@ class BulkUsersController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$users = User::whereIn('id', $user_raw_array)->get();
|
$users = User::whereIn('id', $user_raw_array)->get();
|
||||||
$assets = Asset::whereIn('assigned_to', $user_raw_array)->where('assigned_type', \App\Models\User::class)->get();
|
$assets = Asset::whereIn('assigned_to', $user_raw_array)->where('assigned_type', User::class)->get();
|
||||||
$accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get();
|
$accessories = DB::table('accessories_checkout')->where('assigned_type', User::class)->whereIn('assigned_to', $user_raw_array)->get();
|
||||||
$licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get();
|
$licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get();
|
||||||
$consumables = DB::table('consumables_users')->whereIn('assigned_to', $user_raw_array)->get();
|
$consumables = DB::table('consumables_users')->whereIn('assigned_to', $user_raw_array)->get();
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,8 @@ class UsersController extends Controller
|
||||||
// we have to invoke the
|
// we have to invoke the
|
||||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||||
|
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($user->save()) {
|
if ($user->save()) {
|
||||||
if ($request->filled('groups')) {
|
if ($request->filled('groups')) {
|
||||||
$user->groups()->sync($request->input('groups'));
|
$user->groups()->sync($request->input('groups'));
|
||||||
|
@ -152,7 +154,7 @@ class UsersController extends Controller
|
||||||
$user->notify(new WelcomeNotification($data));
|
$user->notify(new WelcomeNotification($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.create'));
|
return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))->with('success', trans('admin/users/message.success.create'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
return redirect()->back()->withInput()->withErrors($user->getErrors());
|
||||||
|
@ -309,10 +311,11 @@ class UsersController extends Controller
|
||||||
|
|
||||||
// Handle uploaded avatar
|
// Handle uploaded avatar
|
||||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||||
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
|
|
||||||
if ($user->save()) {
|
if ($user->save()) {
|
||||||
// Redirect to the user page
|
// Redirect to the user page
|
||||||
return redirect()->route('users.index')
|
return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))
|
||||||
->with('success', trans('admin/users/message.success.update'));
|
->with('success', trans('admin/users/message.success.update'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,12 @@ class Kernel extends HttpKernel
|
||||||
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||||
\App\Http\Middleware\AssetCountForSidebar::class,
|
\App\Http\Middleware\AssetCountForSidebar::class,
|
||||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'auth:api',
|
'auth:api',
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class CheckLocale
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\App::setLocale(Helper::mapLegacyLocale($language));
|
app()->setLocale(Helper::mapLegacyLocale($language));
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,5 @@ class EncryptCookies extends BaseEncrypter
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected static $serialize = true;
|
protected static $serialize = false;
|
||||||
}
|
}
|
||||||
|
|
76
app/Http/Requests/AccessoryCheckoutRequest.php
Normal file
76
app/Http/Requests/AccessoryCheckoutRequest.php
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
|
class AccessoryCheckoutRequest extends ImageUploadRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return Gate::allows('checkout', new Accessory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($this->accessory) {
|
||||||
|
|
||||||
|
$this->diff = ($this->accessory->numRemaining() - $this->checkout_qty);
|
||||||
|
$this->merge([
|
||||||
|
'checkout_qty' => $this->checkout_qty ?? 1,
|
||||||
|
'number_remaining_after_checkout' => (int) ($this->accessory->numRemaining() - $this->checkout_qty),
|
||||||
|
'number_currently_remaining' => (int) $this->accessory->numRemaining(),
|
||||||
|
'checkout_difference' => (int) $this->diff,
|
||||||
|
]);
|
||||||
|
|
||||||
|
\Log::debug('---------------------------------------------');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
[
|
||||||
|
'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',
|
||||||
|
|
||||||
|
'number_remaining_after_checkout' => [
|
||||||
|
'min:0',
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
],
|
||||||
|
|
||||||
|
'checkout_qty' => [
|
||||||
|
'integer',
|
||||||
|
'lte:number_currently_remaining',
|
||||||
|
'min:1',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
$messages = [
|
||||||
|
'checkout_qty.lte' => trans_choice('admin/accessories/message.checkout.checkout_qty.lte', $this->number_currently_remaining, [
|
||||||
|
'number_currently_remaining' => $this->number_currently_remaining,
|
||||||
|
'checkout_qty' => $this->checkout_qty,
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Intervention\Image\Exception\NotReadableException;
|
use Intervention\Image\Exception\NotReadableException;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
class ImageUploadRequest extends Request
|
class ImageUploadRequest extends Request
|
||||||
{
|
{
|
||||||
|
@ -123,7 +124,7 @@ class ImageUploadRequest extends Request
|
||||||
|
|
||||||
} catch(NotReadableException $e) {
|
} catch(NotReadableException $e) {
|
||||||
Log::debug($e);
|
Log::debug($e);
|
||||||
$validator = \Validator::make([], []);
|
$validator = Validator::make([], []);
|
||||||
$validator->errors()->add($form_fieldname, trans('general.unaccepted_image_type', ['mimetype' => $image->getClientMimeType()]));
|
$validator->errors()->add($form_fieldname, trans('general.unaccepted_image_type', ['mimetype' => $image->getClientMimeType()]));
|
||||||
|
|
||||||
throw new \Illuminate\Validation\ValidationException($validator);
|
throw new \Illuminate\Validation\ValidationException($validator);
|
||||||
|
@ -135,28 +136,28 @@ class ImageUploadRequest extends Request
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove Current image if exists
|
// Remove Current image if exists
|
||||||
if (($item->{$form_fieldname}!='') && (Storage::disk('public')->exists($path.'/'.$item->{$db_fieldname}))) {
|
$item = $this->deleteExistingImage($item, $path, $db_fieldname);
|
||||||
try {
|
|
||||||
Storage::disk('public')->delete($path.'/'.$item->{$form_fieldname});
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::debug('Could not delete old file. '.$path.'/'.$file_name.' does not exist?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$item->{$db_fieldname} = $file_name;
|
$item->{$db_fieldname} = $file_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If the user isn't uploading anything new but wants to delete their old image, do so
|
// If the user isn't uploading anything new but wants to delete their old image, do so
|
||||||
} elseif ($this->input('image_delete') == '1') {
|
} elseif ($this->input('image_delete') == '1') {
|
||||||
Log::debug('Deleting image');
|
$item = $this->deleteExistingImage($item, $path, $db_fieldname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteExistingImage($item, $path = null, $db_fieldname = 'image') {
|
||||||
|
|
||||||
|
if ($item->{$db_fieldname}!='') {
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete($path.'/'.$item->{$db_fieldname});
|
Storage::disk('public')->delete($path.'/'.$item->{$db_fieldname});
|
||||||
$item->{$db_fieldname} = null;
|
$item->{$db_fieldname} = null;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::debug($e);
|
Log::debug($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
|
|
56
app/Http/Requests/StoreAccessoryRequest.php
Normal file
56
app/Http/Requests/StoreAccessoryRequest.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Category;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
|
class StoreAccessoryRequest extends ImageUploadRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return Gate::allows('create', new Accessory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($this->category_id) {
|
||||||
|
if ($category = Category::find($this->category_id)) {
|
||||||
|
$this->merge([
|
||||||
|
'category_type' => $category->category_type ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
['category_type' => 'in:accessory'],
|
||||||
|
parent::rules(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
$messages = ['category_type.in' => trans('admin/accessories/message.invalid_category_type')];
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function response(array $errors)
|
||||||
|
{
|
||||||
|
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Http\Requests\Traits\MayContainCustomFields;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
|
@ -11,6 +12,7 @@ use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
class StoreAssetRequest extends ImageUploadRequest
|
class StoreAssetRequest extends ImageUploadRequest
|
||||||
{
|
{
|
||||||
|
use MayContainCustomFields;
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
*
|
*
|
||||||
|
|
40
app/Http/Requests/Traits/MayContainCustomFields.php
Normal file
40
app/Http/Requests/Traits/MayContainCustomFields.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Traits;
|
||||||
|
|
||||||
|
use App\Models\AssetModel;
|
||||||
|
use App\Models\CustomField;
|
||||||
|
|
||||||
|
trait MayContainCustomFields
|
||||||
|
{
|
||||||
|
// this gets called automatically on a form request
|
||||||
|
public function withValidator($validator)
|
||||||
|
{
|
||||||
|
// find the model
|
||||||
|
if ($this->method() == 'POST') {
|
||||||
|
$asset_model = AssetModel::find($this->model_id);
|
||||||
|
}
|
||||||
|
if ($this->method() == 'PATCH' || $this->method() == 'PUT') {
|
||||||
|
// this is dependent on the asset update request PR
|
||||||
|
$asset_model = $this->asset;
|
||||||
|
}
|
||||||
|
// collect the custom fields in the request
|
||||||
|
$validator->after(function ($validator) use ($asset_model) {
|
||||||
|
$request_fields = $this->collect()->keys()->filter(function ($attributes) {
|
||||||
|
return str_starts_with($attributes, '_snipeit_');
|
||||||
|
});
|
||||||
|
// if there are custom fields, find the one's that don't exist on the model's fieldset and add an error to the validator's error bag
|
||||||
|
if (count($request_fields) > 0) {
|
||||||
|
$request_fields->diff($asset_model->fieldset->fields->pluck('db_column'))
|
||||||
|
->each(function ($request_field_name) use ($request_fields, $validator) {
|
||||||
|
if (CustomField::where('db_column', $request_field_name)->exists()) {
|
||||||
|
$validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found_on_model'));
|
||||||
|
} else {
|
||||||
|
$validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
44
app/Http/Requests/UpdateAssetRequest.php
Normal file
44
app/Http/Requests/UpdateAssetRequest.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\Asset;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UpdateAssetRequest extends ImageUploadRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return Gate::allows('update', $this->asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$rules = array_merge(
|
||||||
|
parent::rules(),
|
||||||
|
(new Asset)->getRules(),
|
||||||
|
// this is to overwrite rulesets that include required, and rewrite unique_undeleted
|
||||||
|
[
|
||||||
|
'model_id' => ['integer', 'exists:models,id,deleted_at,NULL', 'not_array'],
|
||||||
|
'status_id' => ['integer', 'exists:status_labels,id'],
|
||||||
|
'asset_tag' => [
|
||||||
|
'min:1', 'max:255', 'not_array',
|
||||||
|
Rule::unique('assets', 'asset_tag')->ignore($this->asset)->withoutTrashed()
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ class AccessoriesTransformer
|
||||||
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
|
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
|
||||||
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
|
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
|
||||||
'remaining_qty' => (int) $accessory->numRemaining(),
|
'remaining_qty' => (int) $accessory->numRemaining(),
|
||||||
'users_count' => $accessory->users_count,
|
'checkouts_count' => $accessory->checkouts_count,
|
||||||
|
|
||||||
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
|
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
|
||||||
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
|
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
|
||||||
|
@ -66,27 +66,42 @@ class AccessoriesTransformer
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transformCheckedoutAccessory($accessory, $accessory_users, $total)
|
public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $total)
|
||||||
{
|
{
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($accessory_users as $user) {
|
foreach ($accessory_checkouts as $checkout) {
|
||||||
$array[] = [
|
$array[] = [
|
||||||
|
'id' => $checkout->id,
|
||||||
'assigned_pivot_id' => $user->pivot->id,
|
'assigned_to' => $this->transformAssignedTo($checkout),
|
||||||
'id' => (int) $user->id,
|
'checkout_notes' => e($checkout->note),
|
||||||
'username' => e($user->username),
|
'last_checkout' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
|
||||||
'name' => e($user->getFullNameAttribute()),
|
|
||||||
'first_name'=> e($user->first_name),
|
|
||||||
'last_name'=> e($user->last_name),
|
|
||||||
'employee_number' => e($user->employee_num),
|
|
||||||
'checkout_notes' => e($user->pivot->note),
|
|
||||||
'last_checkout' => Helper::getFormattedDateObject($user->pivot->created_at, 'datetime'),
|
|
||||||
'type' => 'user',
|
|
||||||
'available_actions' => ['checkin' => true],
|
'available_actions' => ['checkin' => true],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function transformAssignedTo($accessoryCheckout)
|
||||||
|
{
|
||||||
|
if ($accessoryCheckout->checkedOutToUser()) {
|
||||||
|
return [
|
||||||
|
'id' => (int) $accessoryCheckout->assigned->id,
|
||||||
|
'username' => e($accessoryCheckout->assigned->username),
|
||||||
|
'name' => e($accessoryCheckout->assigned->getFullNameAttribute()),
|
||||||
|
'first_name'=> e($accessoryCheckout->assigned->first_name),
|
||||||
|
'last_name'=> ($accessoryCheckout->assigned->last_name) ? e($accessoryCheckout->assigned->last_name) : null,
|
||||||
|
'email'=> ($accessoryCheckout->assigned->email) ? e($accessoryCheckout->assigned->email) : null,
|
||||||
|
'employee_number' => ($accessoryCheckout->assigned->employee_num) ? e($accessoryCheckout->assigned->employee_num) : null,
|
||||||
|
'type' => 'user',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $accessoryCheckout->assigned ? [
|
||||||
|
'id' => $accessoryCheckout->assigned->id,
|
||||||
|
'name' => e($accessoryCheckout->assigned->display_name),
|
||||||
|
'type' => $accessoryCheckout->assignedType(),
|
||||||
|
] : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,11 +205,11 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function transformCheckedoutActionlog (Collection $accessories_users, $total)
|
public function transformCheckedoutActionlog (Collection $accessories_checkout, $total)
|
||||||
{
|
{
|
||||||
|
|
||||||
$array = array();
|
$array = array();
|
||||||
foreach ($accessories_users as $user) {
|
foreach ($accessories_checkout as $user) {
|
||||||
$array[] = (new UsersTransformer)->transformUser($user);
|
$array[] = (new UsersTransformer)->transformUser($user);
|
||||||
}
|
}
|
||||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||||
|
@ -256,7 +256,7 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $oldRtdName : '';
|
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $oldRtdName : '';
|
||||||
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $newRtdName : '';
|
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $newRtdName : '';
|
||||||
$clean_meta['Default Location'] = $clean_meta['rtd_location_id'];
|
$clean_meta[trans('admin/hardware/form.default_location')] = $clean_meta['rtd_location_id'];
|
||||||
unset($clean_meta['rtd_location_id']);
|
unset($clean_meta['rtd_location_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ". $oldLocationName : '';
|
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ". $oldLocationName : '';
|
||||||
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ". $newLocationName : '';
|
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ". $newLocationName : '';
|
||||||
$clean_meta['Current Location'] = $clean_meta['location_id'];
|
$clean_meta[trans('admin/locations/message.current_location')] = $clean_meta['location_id'];
|
||||||
unset($clean_meta['location_id']);
|
unset($clean_meta['location_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ class ActionlogsTransformer
|
||||||
$clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".$oldModelName;
|
$clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".$oldModelName;
|
||||||
$clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".$newModelName; /** model is required at asset creation */
|
$clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".$newModelName; /** model is required at asset creation */
|
||||||
|
|
||||||
$clean_meta['Model'] = $clean_meta['model_id'];
|
$clean_meta[trans('admin/hardware/form.model')] = $clean_meta['model_id'];
|
||||||
unset($clean_meta['model_id']);
|
unset($clean_meta['model_id']);
|
||||||
}
|
}
|
||||||
if(array_key_exists('company_id', $clean_meta)) {
|
if(array_key_exists('company_id', $clean_meta)) {
|
||||||
|
@ -300,7 +300,7 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
$clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."] ". $oldCompanyName : trans('general.unassigned');
|
$clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."] ". $oldCompanyName : trans('general.unassigned');
|
||||||
$clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ". $newCompanyName : trans('general.unassigned');
|
$clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ". $newCompanyName : trans('general.unassigned');
|
||||||
$clean_meta['Company'] = $clean_meta['company_id'];
|
$clean_meta[trans('general.company')] = $clean_meta['company_id'];
|
||||||
unset($clean_meta['company_id']);
|
unset($clean_meta['company_id']);
|
||||||
}
|
}
|
||||||
if(array_key_exists('supplier_id', $clean_meta)) {
|
if(array_key_exists('supplier_id', $clean_meta)) {
|
||||||
|
@ -313,7 +313,7 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
$clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ". $oldSupplierName : trans('general.unassigned');
|
$clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ". $oldSupplierName : trans('general.unassigned');
|
||||||
$clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ". $newSupplierName : trans('general.unassigned');
|
$clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ". $newSupplierName : trans('general.unassigned');
|
||||||
$clean_meta['Supplier'] = $clean_meta['supplier_id'];
|
$clean_meta[trans('general.supplier')] = $clean_meta['supplier_id'];
|
||||||
unset($clean_meta['supplier_id']);
|
unset($clean_meta['supplier_id']);
|
||||||
}
|
}
|
||||||
if(array_key_exists('status_id', $clean_meta)) {
|
if(array_key_exists('status_id', $clean_meta)) {
|
||||||
|
@ -326,11 +326,11 @@ class ActionlogsTransformer
|
||||||
|
|
||||||
$clean_meta['status_id']['old'] = $clean_meta['status_id']['old'] ? "[id: ".$clean_meta['status_id']['old']."] ". $oldStatusName : trans('general.unassigned');
|
$clean_meta['status_id']['old'] = $clean_meta['status_id']['old'] ? "[id: ".$clean_meta['status_id']['old']."] ". $oldStatusName : trans('general.unassigned');
|
||||||
$clean_meta['status_id']['new'] = $clean_meta['status_id']['new'] ? "[id: ".$clean_meta['status_id']['new']."] ". $newStatusName : trans('general.unassigned');
|
$clean_meta['status_id']['new'] = $clean_meta['status_id']['new'] ? "[id: ".$clean_meta['status_id']['new']."] ". $newStatusName : trans('general.unassigned');
|
||||||
$clean_meta['Status'] = $clean_meta['status_id'];
|
$clean_meta[trans('general.status_label')] = $clean_meta['status_id'];
|
||||||
unset($clean_meta['status_id']);
|
unset($clean_meta['status_id']);
|
||||||
}
|
}
|
||||||
if(array_key_exists('asset_eol_date', $clean_meta)) {
|
if(array_key_exists('asset_eol_date', $clean_meta)) {
|
||||||
$clean_meta['EOL date'] = $clean_meta['asset_eol_date'];
|
$clean_meta[trans('admin/hardware/form.eol_date')] = $clean_meta['asset_eol_date'];
|
||||||
unset($clean_meta['asset_eol_date']);
|
unset($clean_meta['asset_eol_date']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ class ConsumablesTransformer
|
||||||
'checkin' => Gate::allows('checkin', Consumable::class),
|
'checkin' => Gate::allows('checkin', Consumable::class),
|
||||||
'update' => Gate::allows('update', Consumable::class),
|
'update' => Gate::allows('update', Consumable::class),
|
||||||
'delete' => Gate::allows('delete', Consumable::class),
|
'delete' => Gate::allows('delete', Consumable::class),
|
||||||
|
'clone' => (Gate::allows('create', Consumable::class) && ($consumable->deleted_at == '')),
|
||||||
];
|
];
|
||||||
$array += $permissions_array;
|
$array += $permissions_array;
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ class LicenseSeatsTransformer
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($seat_count != 0) {
|
if ($seat_count != 0) {
|
||||||
$array['name'] = 'Seat '.$seat_count;
|
$array['name'] = trans('admin/licenses/general.seat_count', ['count' => $seat_count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
|
|
|
@ -45,6 +45,10 @@ class LicensesTransformer
|
||||||
'maintained' => ($license->maintained == 1) ? true : false,
|
'maintained' => ($license->maintained == 1) ? true : false,
|
||||||
'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id, 'name'=> e($license->supplier->name)] : null,
|
'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id, 'name'=> e($license->supplier->name)] : null,
|
||||||
'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null,
|
'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null,
|
||||||
|
'created_by' => ($license->adminuser) ? [
|
||||||
|
'id' => (int) $license->adminuser->id,
|
||||||
|
'name'=> e($license->adminuser->present()->fullName()),
|
||||||
|
] : null,
|
||||||
'created_at' => Helper::getFormattedDateObject($license->created_at, 'datetime'),
|
'created_at' => Helper::getFormattedDateObject($license->created_at, 'datetime'),
|
||||||
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
|
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
|
||||||
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
|
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
|
||||||
|
|
|
@ -3,14 +3,10 @@
|
||||||
namespace App\Importer;
|
namespace App\Importer;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\AssetModel;
|
|
||||||
use App\Models\Statuslabel;
|
use App\Models\Statuslabel;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Events\CheckoutableCheckedIn;
|
use App\Events\CheckoutableCheckedIn;
|
||||||
use Carbon\CarbonImmutable;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class AssetImporter extends ItemImporter
|
class AssetImporter extends ItemImporter
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,6 +67,7 @@ class UserImporter extends ItemImporter
|
||||||
$this->item['vip'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'vip'))) ==1 ) ? '1' : 0;
|
$this->item['vip'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'vip'))) ==1 ) ? '1' : 0;
|
||||||
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'autoassign_licenses'))) ==1 ) ? '1' : 0;
|
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'autoassign_licenses'))) ==1 ) ? '1' : 0;
|
||||||
|
|
||||||
|
$this->handleEmptyStringsForDates();
|
||||||
|
|
||||||
$user_department = trim($this->findCsvMatch($row, 'department'));
|
$user_department = trim($this->findCsvMatch($row, 'department'));
|
||||||
if ($this->shouldUpdateField($user_department)) {
|
if ($this->shouldUpdateField($user_department)) {
|
||||||
|
@ -179,4 +180,22 @@ class UserImporter extends ItemImporter
|
||||||
{
|
{
|
||||||
$this->send_welcome = $send;
|
$this->send_welcome = $send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since the findCsvMatch() method will set '' for columns that are present but empty,
|
||||||
|
* we need to set those empty strings to null to avoid passing bad data to the database
|
||||||
|
* (ie ending up with 0000-00-00 instead of the intended null).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function handleEmptyStringsForDates(): void
|
||||||
|
{
|
||||||
|
if ($this->item['start_date'] === '') {
|
||||||
|
$this->item['start_date'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->item['end_date'] === '') {
|
||||||
|
$this->item['end_date'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Accessory extends SnipeModel
|
||||||
'company_id' => 'integer|nullable',
|
'company_id' => 'integer|nullable',
|
||||||
'min_amt' => 'integer|min:0|nullable',
|
'min_amt' => 'integer|min:0|nullable',
|
||||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,9 +253,10 @@ class Accessory extends SnipeModel
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
*/
|
*/
|
||||||
public function users()
|
public function checkouts()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id', 'created_at', 'note')->withTrashed();
|
return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id')
|
||||||
|
->with('assignedTo');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,7 +268,9 @@ class Accessory extends SnipeModel
|
||||||
*/
|
*/
|
||||||
public function hasUsers()
|
public function hasUsers()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->count();
|
return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id')
|
||||||
|
->where('assigned_type', User::class)
|
||||||
|
->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,11 +332,24 @@ class Accessory extends SnipeModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check how many items within an accessory are checked out
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v5.0]
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function numCheckedOut()
|
||||||
|
{
|
||||||
|
return $this->checkouts_count ?? $this->checkouts()->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check how many items of an accessory remain.
|
* Check how many items of an accessory remain.
|
||||||
*
|
*
|
||||||
* In order to use this model method, you MUST call withCount('users as users_count')
|
* In order to use this model method, you MUST call withCount('checkouts as checkouts_count')
|
||||||
* on the eloquent query in the controller, otherwise $this->>users_count will be null and
|
* on the eloquent query in the controller, otherwise $this->checkouts_count will be null and
|
||||||
* bad things happen.
|
* bad things happen.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
@ -342,11 +358,11 @@ class Accessory extends SnipeModel
|
||||||
*/
|
*/
|
||||||
public function numRemaining()
|
public function numRemaining()
|
||||||
{
|
{
|
||||||
$checkedout = $this->users_count;
|
$checkedout = $this->numCheckedOut();
|
||||||
$total = $this->qty;
|
$total = $this->qty;
|
||||||
$remaining = $total - $checkedout;
|
$remaining = $total - $checkedout;
|
||||||
|
|
||||||
return (int) $remaining;
|
return $remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -357,12 +373,12 @@ class Accessory extends SnipeModel
|
||||||
*/
|
*/
|
||||||
public function declinedCheckout(User $declinedBy, $signature)
|
public function declinedCheckout(User $declinedBy, $signature)
|
||||||
{
|
{
|
||||||
if (is_null($accessory_user = \DB::table('accessories_users')->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) {
|
if (is_null($accessory_checkout = AccessoryCheckout::userAssigned()->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) {
|
||||||
// Redirect to the accessory management page with error
|
// Redirect to the accessory management page with error
|
||||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessory_user->limit(1)->delete();
|
$accessory_checkout->limit(1)->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
148
app/Models/AccessoryCheckout.php
Executable file
148
app/Models/AccessoryCheckout.php
Executable file
|
@ -0,0 +1,148 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\Searchable;
|
||||||
|
use App\Presenters\Presentable;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model for Accessories.
|
||||||
|
*
|
||||||
|
* @version v1.0
|
||||||
|
*/
|
||||||
|
class AccessoryCheckout extends Model
|
||||||
|
{
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
|
protected $fillable = ['user_id', 'accessory_id', 'assigned_to', 'assigned_type', 'note'];
|
||||||
|
protected $table = 'accessories_checkout';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes the accessory checkout -> accessory relationship
|
||||||
|
*
|
||||||
|
* @author [A. Kroeger]
|
||||||
|
* @since [v7.0.9]
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
|
*/
|
||||||
|
public function accessory()
|
||||||
|
{
|
||||||
|
return $this->hasOne(\App\Models\Accessory::class, 'accessory_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes the accessory checkout -> user relationship
|
||||||
|
*
|
||||||
|
* @author [A. Kroeger]
|
||||||
|
* @since [v7.0.9]
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->hasOne(\App\Models\User::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the target this asset is checked out to
|
||||||
|
*
|
||||||
|
* @author [A. Kroeger]
|
||||||
|
* @since [v7.0]
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
|
*/
|
||||||
|
public function assignedTo()
|
||||||
|
{
|
||||||
|
return $this->morphTo('assigned', 'assigned_type', 'assigned_to')->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the lowercased name of the type of target the asset is assigned to
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v4.0]
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function assignedType()
|
||||||
|
{
|
||||||
|
return $this->assigned_type ? strtolower(class_basename($this->assigned_type)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the accessory is checked out to a user
|
||||||
|
*
|
||||||
|
* Even though we allow allow for checkout to things beyond users
|
||||||
|
* this method is an easy way of seeing if we are checked out to a user.
|
||||||
|
*
|
||||||
|
* @author [A. Kroeger]
|
||||||
|
* @since [v7.0]
|
||||||
|
*/
|
||||||
|
public function checkedOutToUser(): bool
|
||||||
|
{
|
||||||
|
return $this->assignedType() === Asset::USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeUserAssigned(Builder $query): void
|
||||||
|
{
|
||||||
|
$query->where('assigned_type', '=', User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run additional, advanced searches.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param array $terms The search terms
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
public function advancedTextSearch(Builder $query, array $terms)
|
||||||
|
{
|
||||||
|
|
||||||
|
$userQuery = User::where(function ($query) use ($terms) {
|
||||||
|
foreach ($terms as $term) {
|
||||||
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('first_name', 'like', $search_str)
|
||||||
|
->orWhere('last_name', 'like', $search_str)
|
||||||
|
->orWhere('note', 'like', $search_str);
|
||||||
|
}
|
||||||
|
})->select('id');
|
||||||
|
|
||||||
|
$locationQuery = Location::where(function ($query) use ($terms) {
|
||||||
|
foreach ($terms as $term) {
|
||||||
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('name', 'like', $search_str);
|
||||||
|
}
|
||||||
|
})->select('id');
|
||||||
|
|
||||||
|
$assetQuery = Asset::where(function ($query) use ($terms) {
|
||||||
|
foreach ($terms as $term) {
|
||||||
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('name', 'like', $search_str);
|
||||||
|
}
|
||||||
|
})->select('id');
|
||||||
|
|
||||||
|
$query->where(function ($query) use ($userQuery) {
|
||||||
|
$query->where('assigned_type', User::class)
|
||||||
|
->whereIn('assigned_to', $userQuery);
|
||||||
|
})->orWhere(function($query) use ($locationQuery) {
|
||||||
|
$query->where('assigned_type', Location::class)
|
||||||
|
->whereIn('assigned_to', $locationQuery);
|
||||||
|
})->orWhere(function($query) use ($assetQuery) {
|
||||||
|
$query->where('assigned_type', Asset::class)
|
||||||
|
->whereIn('assigned_to', $assetQuery);
|
||||||
|
})->orWhere(function($query) use ($terms) {
|
||||||
|
foreach ($terms as $term) {
|
||||||
|
$search_str = '%' . $term . '%';
|
||||||
|
$query->where('note', 'like', $search_str);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -97,35 +97,38 @@ class Asset extends Depreciable
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'model_id' => 'required|integer|exists:models,id,deleted_at,NULL|not_array',
|
'model_id' => ['required', 'integer', 'exists:models,id,deleted_at,NULL', 'not_array'],
|
||||||
'status_id' => 'required|integer|exists:status_labels,id',
|
'status_id' => ['required', 'integer', 'exists:status_labels,id'],
|
||||||
'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag|not_array',
|
'asset_tag' => ['required', 'min:1', 'max:255', 'unique_undeleted:assets,asset_tag', 'not_array'],
|
||||||
'name' => 'nullable|max:255',
|
'name' => ['nullable', 'max:255'],
|
||||||
'company_id' => 'nullable|integer|exists:companies,id',
|
'company_id' => ['nullable', 'integer', 'exists:companies,id'],
|
||||||
'warranty_months' => 'nullable|numeric|digits_between:0,240',
|
'warranty_months' => ['nullable', 'numeric', 'digits_between:0,240'],
|
||||||
'last_checkout' => 'nullable|date_format:Y-m-d H:i:s',
|
'last_checkout' => ['nullable', 'date_format:Y-m-d H:i:s'],
|
||||||
'last_checkin' => 'nullable|date_format:Y-m-d H:i:s',
|
'last_checkin' => ['nullable', 'date_format:Y-m-d H:i:s'],
|
||||||
'expected_checkin' => 'nullable|date',
|
'expected_checkin' => ['nullable', 'date'],
|
||||||
'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s',
|
'last_audit_date' => ['nullable', 'date_format:Y-m-d H:i:s'],
|
||||||
// 'next_audit_date' => 'nullable|date|after:last_audit_date',
|
'next_audit_date' => ['nullable', 'date'],
|
||||||
'next_audit_date' => 'nullable|date',
|
//'after:last_audit_date'],
|
||||||
'location_id' => 'nullable|exists:locations,id',
|
'location_id' => ['nullable', 'exists:locations,id'],
|
||||||
'rtd_location_id' => 'nullable|exists:locations,id',
|
'rtd_location_id' => ['nullable', 'exists:locations,id'],
|
||||||
'purchase_date' => 'nullable|date|date_format:Y-m-d',
|
'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'],
|
||||||
'serial' => 'nullable|unique_undeleted:assets,serial',
|
'serial' => ['nullable', 'unique_undeleted:assets,serial'],
|
||||||
'purchase_cost' => 'nullable|numeric|gte:0',
|
'purchase_cost' => ['nullable', 'numeric', 'gte:0'],
|
||||||
'supplier_id' => 'nullable|exists:suppliers,id',
|
'supplier_id' => ['nullable', 'exists:suppliers,id'],
|
||||||
'asset_eol_date' => 'nullable|date',
|
'asset_eol_date' => ['nullable', 'date'],
|
||||||
'eol_explicit' => 'nullable|boolean',
|
'eol_explicit' => ['nullable', 'boolean'],
|
||||||
'byod' => 'nullable|boolean',
|
'byod' => ['nullable', 'boolean'],
|
||||||
'order_number' => 'nullable|string|max:191',
|
'order_number' => ['nullable', 'string', 'max:191'],
|
||||||
'notes' => 'nullable|string|max:65535',
|
'notes' => ['nullable', 'string', 'max:65535'],
|
||||||
'assigned_to' => 'nullable|integer',
|
'assigned_to' => ['nullable', 'integer'],
|
||||||
'requestable' => 'nullable|boolean',
|
'requestable' => ['nullable', 'boolean'],
|
||||||
|
'assigned_user' => ['nullable', 'exists:users,id,deleted_at,NULL'],
|
||||||
|
'assigned_location' => ['nullable', 'exists:locations,id,deleted_at,NULL'],
|
||||||
|
'assigned_asset' => ['nullable', 'exists:assets,id,deleted_at,NULL']
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
|
|
|
@ -205,7 +205,11 @@ class Component extends SnipeModel
|
||||||
public function numCheckedOut()
|
public function numCheckedOut()
|
||||||
{
|
{
|
||||||
$checkedout = 0;
|
$checkedout = 0;
|
||||||
foreach ($this->assets as $checkout) {
|
|
||||||
|
// In case there are elements checked out to assets that belong to a different company
|
||||||
|
// than this asset and full multiple company support is on we'll remove the global scope,
|
||||||
|
// so they are included in the count.
|
||||||
|
foreach ($this->assets()->withoutGlobalScope(new CompanyableScope)->get() as $checkout) {
|
||||||
$checkedout += $checkout->pivot->assigned_qty;
|
$checkedout += $checkout->pivot->assigned_qty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use EasySlugger\Utf8Slugger;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
class CustomField extends Model
|
class CustomField extends Model
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,17 +158,20 @@ class Depreciable extends SnipeModel
|
||||||
|
|
||||||
public function time_until_depreciated()
|
public function time_until_depreciated()
|
||||||
{
|
{
|
||||||
// @link http://www.php.net/manual/en/class.datetime.php
|
if ($this->depreciated_date()) {
|
||||||
$d1 = new \DateTime();
|
// @link http://www.php.net/manual/en/class.datetime.php
|
||||||
$d2 = $this->depreciated_date();
|
$d1 = new \DateTime();
|
||||||
|
$d2 = $this->depreciated_date();
|
||||||
|
|
||||||
// @link http://www.php.net/manual/en/class.dateinterval.php
|
// @link http://www.php.net/manual/en/class.dateinterval.php
|
||||||
$interval = $d1->diff($d2);
|
$interval = $d1->diff($d2);
|
||||||
if (! $interval->invert) {
|
if (! $interval->invert) {
|
||||||
return $interval;
|
return $interval;
|
||||||
} else {
|
} else {
|
||||||
return new \DateInterval('PT0S'); //null interval (zero seconds from now)
|
return new \DateInterval('PT0S'); //null interval (zero seconds from now)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function depreciated_date()
|
public function depreciated_date()
|
||||||
|
|
|
@ -229,6 +229,7 @@ class Ldap extends Model
|
||||||
$item['department'] = $ldapattributes[$ldap_result_dept][0] ?? '';
|
$item['department'] = $ldapattributes[$ldap_result_dept][0] ?? '';
|
||||||
$item['manager'] = $ldapattributes[$ldap_result_manager][0] ?? '';
|
$item['manager'] = $ldapattributes[$ldap_result_manager][0] ?? '';
|
||||||
$item['location'] = $ldapattributes[$ldap_result_location][0] ?? '';
|
$item['location'] = $ldapattributes[$ldap_result_location][0] ?? '';
|
||||||
|
$item['locale'] = app()->getLocale();
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +240,7 @@ class Ldap extends Model
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @param $ldapatttibutes
|
* @param $ldapatttibutes
|
||||||
* @return array|bool
|
* @return User | bool
|
||||||
*/
|
*/
|
||||||
public static function createUserFromLdap($ldapatttibutes, $password)
|
public static function createUserFromLdap($ldapatttibutes, $password)
|
||||||
{
|
{
|
||||||
|
@ -252,6 +253,7 @@ class Ldap extends Model
|
||||||
$user->last_name = $item['lastname'];
|
$user->last_name = $item['lastname'];
|
||||||
$user->username = $item['username'];
|
$user->username = $item['username'];
|
||||||
$user->email = $item['email'];
|
$user->email = $item['email'];
|
||||||
|
$user->locale = $item['locale'];
|
||||||
$user->password = $user->noPassword();
|
$user->password = $user->noPassword();
|
||||||
|
|
||||||
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
||||||
|
|
|
@ -50,7 +50,7 @@ class License extends Depreciable
|
||||||
'category_id' => 'required|exists:categories,id',
|
'category_id' => 'required|exists:categories,id',
|
||||||
'company_id' => 'integer|nullable',
|
'company_id' => 'integer|nullable',
|
||||||
'purchase_cost'=> 'numeric|nullable|gte:0',
|
'purchase_cost'=> 'numeric|nullable|gte:0',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable|max:10',
|
'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id',
|
||||||
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||||
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||||
'min_amt' => 'numeric|nullable|gte:0',
|
'min_amt' => 'numeric|nullable|gte:0',
|
||||||
|
@ -736,4 +736,17 @@ class License extends Depreciable
|
||||||
return $query->leftJoin('companies as companies', 'licenses.company_id', '=', 'companies.id')->select('licenses.*')
|
return $query->leftJoin('companies as companies', 'licenses.company_id', '=', 'companies.id')->select('licenses.*')
|
||||||
->orderBy('companies.name', $order);
|
->orderBy('companies.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query builder scope to order on the user that created it
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
|
* @param text $order Order
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
|
*/
|
||||||
|
public function scopeOrderCreatedBy($query, $order)
|
||||||
|
{
|
||||||
|
return $query->leftJoin('users as users_sort', 'licenses.user_id', '=', 'users_sort.id')->select('licenses.*')->orderBy('users_sort.first_name', $order)->orderBy('users_sort.last_name', $order);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -108,10 +108,11 @@ class Location extends SnipeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
return Gate::allows('delete', $this)
|
return Gate::allows('delete', $this)
|
||||||
&& ($this->assets_count === 0)
|
&& ($this->assets_count == 0)
|
||||||
&& ($this->assigned_assets_count === 0)
|
&& ($this->assigned_assets_count == 0)
|
||||||
&& ($this->children_count === 0)
|
&& ($this->children_count == 0)
|
||||||
&& ($this->users_count === 0);
|
&& ($this->accessories_count == 0)
|
||||||
|
&& ($this->users_count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,9 +22,9 @@ class Manufacturer extends SnipeModel
|
||||||
// Declare the rules for the form validation
|
// Declare the rules for the form validation
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'name' => 'required|min:2|max:255|unique:manufacturers,name,NULL,id,deleted_at,NULL',
|
'name' => 'required|min:2|max:255|unique:manufacturers,name,NULL,id,deleted_at,NULL',
|
||||||
'url' => 'url|nullable',
|
'url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://',
|
||||||
'support_email' => 'email|nullable',
|
'support_email' => 'email|nullable',
|
||||||
'support_url' => 'nullable|url',
|
'support_url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://',
|
||||||
'warranty_lookup_url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://'
|
'warranty_lookup_url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||||
*/
|
*/
|
||||||
public function accessories()
|
public function accessories()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_users', 'assigned_to', 'accessory_id')
|
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_checkout', 'assigned_to', 'accessory_id')
|
||||||
->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id');
|
->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
$this->item = $accessory;
|
$this->item = $accessory;
|
||||||
$this->admin = $checkedOutBy;
|
$this->admin = $checkedOutBy;
|
||||||
$this->note = $note;
|
$this->note = $note;
|
||||||
|
$this->checkout_qty = $accessory->checkout_qty;
|
||||||
$this->target = $checkedOutTo;
|
$this->target = $checkedOutTo;
|
||||||
$this->acceptance = $acceptance;
|
$this->acceptance = $acceptance;
|
||||||
$this->settings = Setting::getSettings();
|
$this->settings = Setting::getSettings();
|
||||||
|
@ -107,7 +108,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->present()->name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
|
@ -127,6 +128,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||||
->fact(trans('mail.assigned_to'), $target->present()->name)
|
->fact(trans('mail.assigned_to'), $target->present()->name)
|
||||||
|
->fact(trans('general.qty'), $this->checkout_qty)
|
||||||
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
|
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
|
||||||
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->present()->fullName())
|
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->present()->fullName())
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
|
@ -184,6 +186,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
'eula' => $eula,
|
'eula' => $eula,
|
||||||
'req_accept' => $req_accept,
|
'req_accept' => $req_accept,
|
||||||
'accept_url' => $accept_url,
|
'accept_url' => $accept_url,
|
||||||
|
'checkout_qty' => $this->checkout_qty,
|
||||||
])
|
])
|
||||||
->subject(trans('mail.Confirm_accessory_delivery'));
|
->subject(trans('mail.Confirm_accessory_delivery'));
|
||||||
}
|
}
|
||||||
|
|
73
app/Notifications/UnacceptedAssetReminderNotification.php
Normal file
73
app/Notifications/UnacceptedAssetReminderNotification.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class UnacceptedAssetReminderNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($checkout_info, $count)
|
||||||
|
{
|
||||||
|
$this->count = $count;
|
||||||
|
$this->target = $checkout_info['acceptance']->assignedTo;
|
||||||
|
$this->acceptance = $checkout_info['acceptance'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function via()
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||||
|
*/
|
||||||
|
public function toMail()
|
||||||
|
{
|
||||||
|
$accept_url = route('account.accept');
|
||||||
|
$message = (new MailMessage)->markdown('notifications.markdown.asset-reminder',
|
||||||
|
[
|
||||||
|
'count' => $this->count,
|
||||||
|
'assigned_to' => $this->target->present()->fullName,
|
||||||
|
'link' => route('account.accept'),
|
||||||
|
'accept_url' => $accept_url,
|
||||||
|
])
|
||||||
|
->subject(trans('mail.unaccepted_asset_reminder'));
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($notifiable)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,7 +90,7 @@ class AccessoryPresenter extends Presenter
|
||||||
'visible' => false,
|
'visible' => false,
|
||||||
'title' => trans('admin/accessories/general.remaining'),
|
'title' => trans('admin/accessories/general.remaining'),
|
||||||
],[
|
],[
|
||||||
'field' => 'users_count',
|
'field' => 'checkouts_count',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
|
|
|
@ -556,13 +556,12 @@ class AssetPresenter extends Presenter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to take user created warranty URL and dynamically fill in the needed values per asset
|
* Used to take user created URL and dynamically fill in the needed values per asset
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function dynamicWarrantyUrl()
|
public function dynamicUrl($dynamic_url)
|
||||||
{
|
{
|
||||||
$warranty_lookup_url = $this->model->model->manufacturer->warranty_lookup_url;
|
$url = (str_replace('{LOCALE}',\App\Models\Setting::getSettings()->locale, $dynamic_url));
|
||||||
$url = (str_replace('{LOCALE}',\App\Models\Setting::getSettings()->locale, $warranty_lookup_url));
|
|
||||||
$url = (str_replace('{SERIAL}', urlencode($this->model->serial), $url));
|
$url = (str_replace('{SERIAL}', urlencode($this->model->serial), $url));
|
||||||
$url = (str_replace('{MODEL_NAME}', urlencode($this->model->model->name), $url));
|
$url = (str_replace('{MODEL_NAME}', urlencode($this->model->model->name), $url));
|
||||||
$url = (str_replace('{MODEL_NUMBER}', urlencode($this->model->model->model_number), $url));
|
$url = (str_replace('{MODEL_NUMBER}', urlencode($this->model->model->model_number), $url));
|
||||||
|
|
|
@ -158,6 +158,13 @@ class LicensePresenter extends Presenter
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'visible' => false,
|
'visible' => false,
|
||||||
'title' => trans('general.order_number'),
|
'title' => trans('general.order_number'),
|
||||||
|
], [
|
||||||
|
'field' => 'created_by',
|
||||||
|
'searchable' => false,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.admin'),
|
||||||
|
'visible' => false,
|
||||||
|
'formatter' => 'usersLinkObjFormatter',
|
||||||
], [
|
], [
|
||||||
'field' => 'created_at',
|
'field' => 'created_at',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
|
|
|
@ -445,26 +445,30 @@ class UserPresenter extends Presenter
|
||||||
return Storage::disk('public')->url('avatars/'.e($this->avatar));
|
return Storage::disk('public')->url('avatars/'.e($this->avatar));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a default avatar
|
|
||||||
if (Setting::getSettings()->default_avatar!= '') {
|
// If the default is system default
|
||||||
|
if (Setting::getSettings()->default_avatar == 'default.png') {
|
||||||
|
return Storage::disk('public')->url('default.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a custom default avatar
|
||||||
|
if (Setting::getSettings()->default_avatar != '') {
|
||||||
return Storage::disk('public')->url('avatars/'.e(Setting::getSettings()->default_avatar));
|
return Storage::disk('public')->url('avatars/'.e(Setting::getSettings()->default_avatar));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to Gravatar if the settings allow loading remote scripts
|
// If there is no default and no custom avatar, check for gravatar
|
||||||
if (Setting::getSettings()->load_remote == '1') {
|
if ((Setting::getSettings()->load_remote == '1') && (Setting::getSettings()->default_avatar == '')) {
|
||||||
if ($this->model->gravatar != '') {
|
|
||||||
|
|
||||||
|
if ($this->model->gravatar != '') {
|
||||||
$gravatar = md5(strtolower(trim($this->model->gravatar)));
|
$gravatar = md5(strtolower(trim($this->model->gravatar)));
|
||||||
return '//gravatar.com/avatar/'.$gravatar;
|
return '//gravatar.com/avatar/'.$gravatar;
|
||||||
|
|
||||||
} elseif ($this->email != '') {
|
} elseif ($this->email != '') {
|
||||||
|
|
||||||
$gravatar = md5(strtolower(trim($this->email)));
|
$gravatar = md5(strtolower(trim($this->email)));
|
||||||
return '//gravatar.com/avatar/'.$gravatar;
|
return '//gravatar.com/avatar/'.$gravatar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,11 +87,11 @@ class AuthServiceProvider extends ServiceProvider
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->registerPolicies();
|
$this->registerPolicies();
|
||||||
//Passport::routes(); //this is no longer required in newer passport versions
|
|
||||||
Passport::tokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
Passport::tokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||||
Passport::refreshTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
Passport::refreshTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||||
Passport::personalAccessTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
Passport::personalAccessTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||||
Passport::withCookieSerialization();
|
|
||||||
|
Passport::cookie(config('passport.cookie_name'));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
25
app/Providers/BladeServiceProvider.php
Normal file
25
app/Providers/BladeServiceProvider.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Blade;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class BladeServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
Blade::anonymousComponentPath(__DIR__ . '/../../resources/views/blade');
|
||||||
|
}
|
||||||
|
}
|
32
app/Providers/LivewireServiceProvider.php
Normal file
32
app/Providers/LivewireServiceProvider.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
class LivewireServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
Livewire::setUpdateRoute(function ($handle) {
|
||||||
|
return Route::post('/' . config('livewire.url_prefix') . '/livewire/update', $handle);
|
||||||
|
});
|
||||||
|
|
||||||
|
Livewire::setScriptRoute(function ($handle) {
|
||||||
|
return Route::get('/' . config('livewire.url_prefix') . '/livewire/livewire.js', $handle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service provider handles a few custom validation rules.
|
* This service provider handles a few custom validation rules.
|
||||||
|
@ -66,7 +66,6 @@ class ValidationServiceProvider extends ServiceProvider
|
||||||
* `unique_undeleted:table,fieldname` in your rules out of the box
|
* `unique_undeleted:table,fieldname` in your rules out of the box
|
||||||
*/
|
*/
|
||||||
Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) {
|
Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) {
|
||||||
|
|
||||||
if (count($parameters)) {
|
if (count($parameters)) {
|
||||||
|
|
||||||
// This is a bit of a shim, but serial doesn't have any other rules around it other than that it's nullable
|
// This is a bit of a shim, but serial doesn't have any other rules around it other than that it's nullable
|
||||||
|
|
|
@ -107,7 +107,7 @@ class Label implements View
|
||||||
|
|
||||||
if ($settings->alt_barcode_enabled) {
|
if ($settings->alt_barcode_enabled) {
|
||||||
if ($template->getSupport1DBarcode()) {
|
if ($template->getSupport1DBarcode()) {
|
||||||
$barcode1DType = $settings->alt_barcode;
|
$barcode1DType = $settings->label2_1d_type;
|
||||||
if ($barcode1DType != 'none') {
|
if ($barcode1DType != 'none') {
|
||||||
$assetData->put('barcode1d', (object)[
|
$assetData->put('barcode1d', (object)[
|
||||||
'type' => $barcode1DType,
|
'type' => $barcode1DType,
|
||||||
|
|
|
@ -311,8 +311,10 @@ return [
|
||||||
App\Providers\ValidationServiceProvider::class,
|
App\Providers\ValidationServiceProvider::class,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Custom service provider
|
* Custom Service Providers...
|
||||||
*/
|
*/
|
||||||
|
App\Providers\BladeServiceProvider::class,
|
||||||
|
App\Providers\LivewireServiceProvider::class,
|
||||||
App\Providers\MacroServiceProvider::class,
|
App\Providers\MacroServiceProvider::class,
|
||||||
App\Providers\SamlServiceProvider::class,
|
App\Providers\SamlServiceProvider::class,
|
||||||
|
|
||||||
|
@ -426,5 +428,5 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'escape_formulas' => env('CSV_ESCAPE_FORMULAS', true),
|
'escape_formulas' => env('CSV_ESCAPE_FORMULAS', true),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -139,7 +139,7 @@ return [
|
||||||
'to' => env('MAIL_BACKUP_NOTIFICATION_ADDRESS', null),
|
'to' => env('MAIL_BACKUP_NOTIFICATION_ADDRESS', null),
|
||||||
|
|
||||||
'from' => [
|
'from' => [
|
||||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
'address' => env('MAIL_FROM_ADDR', 'hello@example.com'),
|
||||||
'name' => env('MAIL_FROM_NAME', 'Example'),
|
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
|
@ -157,4 +157,21 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'pagination_theme' => 'tailwind',
|
'pagination_theme' => 'tailwind',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|---------------------------------------------------------------------------
|
||||||
|
| URL Prefix
|
||||||
|
|---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default, Livewire sends network requests to {app.com}/livewire/update
|
||||||
|
| while javascript assets are served via {app.com}/livewire/livewire.js
|
||||||
|
| If you need to adjust the prefix of those urls you can do it below.
|
||||||
|
|
|
||||||
|
| Defining a prefix will result in the following url
|
||||||
|
| {app.com}/{prefix}/livewire/{update|livewire.js}
|
||||||
|
| Note: do not include the leading or trailing /
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'url_prefix' => env('LIVEWIRE_URL_PREFIX', null),
|
||||||
];
|
];
|
||||||
|
|
|
@ -14,4 +14,5 @@ return [
|
||||||
'private_key' => env('PASSPORT_PRIVATE_KEY'),
|
'private_key' => env('PASSPORT_PRIVATE_KEY'),
|
||||||
'public_key' => env('PASSPORT_PUBLIC_KEY'),
|
'public_key' => env('PASSPORT_PUBLIC_KEY'),
|
||||||
'expiration_years' => env('API_TOKEN_EXPIRATION_YEARS', 20),
|
'expiration_years' => env('API_TOKEN_EXPIRATION_YEARS', 20),
|
||||||
|
'cookie_name' => env('PASSPORT_COOKIE_NAME', 'snipeit_passport_token'),
|
||||||
];
|
];
|
||||||
|
|
|
@ -44,12 +44,6 @@ return [
|
||||||
'secret' => env('STRIPE_SECRET'),
|
'secret' => env('STRIPE_SECRET'),
|
||||||
],
|
],
|
||||||
|
|
||||||
'baremetrics' => [
|
|
||||||
'enabled' => env('ENABLE_BMPAY', false),
|
|
||||||
'app_key' => env('BMPAY_PUBLIC_KEY', null),
|
|
||||||
'stripe_id' => env('BMPAY_STRIPE_ID', null),
|
|
||||||
],
|
|
||||||
|
|
||||||
'google' => [
|
'google' => [
|
||||||
'maps_api_key' => env('GOOGLE_MAPS_API'),
|
'maps_api_key' => env('GOOGLE_MAPS_API'),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
return array (
|
return array (
|
||||||
'app_version' => 'v7.0.9',
|
'app_version' => 'v7.0.10',
|
||||||
'full_app_version' => 'v7.0.9 - build 14371-g1a541ce22',
|
'full_app_version' => 'v7.0.10 - build 14684-gc2bcc2e2d',
|
||||||
'build_version' => '14371',
|
'build_version' => '14684',
|
||||||
'prerelease_version' => '',
|
'prerelease_version' => '',
|
||||||
'hash_version' => 'g1a541ce22',
|
'hash_version' => 'gc2bcc2e2d',
|
||||||
'full_hash' => 'v7.0.9-119-g1a541ce22',
|
'full_hash' => 'v7.0.10-311-gc2bcc2e2d',
|
||||||
'branch' => 'develop',
|
'branch' => 'master',
|
||||||
);
|
);
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
|
use App\Models\AccessoryCheckout;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Manufacturer;
|
use App\Models\Manufacturer;
|
||||||
|
@ -125,11 +126,12 @@ class AccessoryFactory extends Factory
|
||||||
})->afterCreating(function ($accessory) {
|
})->afterCreating(function ($accessory) {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
|
|
||||||
$accessory->users()->attach($accessory->id, [
|
$accessory->checkouts()->create([
|
||||||
'accessory_id' => $accessory->id,
|
'accessory_id' => $accessory->id,
|
||||||
'created_at' => now(),
|
'created_at' => Carbon::now(),
|
||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
'assigned_to' => $user->id,
|
'assigned_to' => $user->id,
|
||||||
|
'assigned_type' => User::class,
|
||||||
'note' => '',
|
'note' => '',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -145,11 +147,12 @@ class AccessoryFactory extends Factory
|
||||||
public function checkedOutToUser(User $user = null)
|
public function checkedOutToUser(User $user = null)
|
||||||
{
|
{
|
||||||
return $this->afterCreating(function (Accessory $accessory) use ($user) {
|
return $this->afterCreating(function (Accessory $accessory) use ($user) {
|
||||||
$accessory->users()->attach($accessory->id, [
|
$accessory->checkouts()->create([
|
||||||
'accessory_id' => $accessory->id,
|
'accessory_id' => $accessory->id,
|
||||||
'created_at' => Carbon::now(),
|
'created_at' => Carbon::now(),
|
||||||
'user_id' => 1,
|
'user_id' => 1,
|
||||||
'assigned_to' => $user->id ?? User::factory()->create()->id,
|
'assigned_to' => $user->id ?? User::factory()->create()->id,
|
||||||
|
'assigned_type' => User::class,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ class AssetFactory extends Factory
|
||||||
'assigned_type' => null,
|
'assigned_type' => null,
|
||||||
'next_audit_date' => null,
|
'next_audit_date' => null,
|
||||||
'last_checkout' => null,
|
'last_checkout' => null,
|
||||||
|
'asset_eol_date' => null
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,6 +355,17 @@ class AssetFactory extends Factory
|
||||||
return $this->state(['requestable' => false]);
|
return $this->state(['requestable' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function noPurchaseOrEolDate()
|
||||||
|
{
|
||||||
|
return $this->afterCreating(function (Asset $asset) {
|
||||||
|
$asset->update([
|
||||||
|
'purchase_date' => null,
|
||||||
|
'asset_eol_date' => null
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function hasEncryptedCustomField(CustomField $field = null)
|
public function hasEncryptedCustomField(CustomField $field = null)
|
||||||
{
|
{
|
||||||
return $this->state(function () use ($field) {
|
return $this->state(function () use ($field) {
|
||||||
|
@ -372,7 +384,6 @@ class AssetFactory extends Factory
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This allows bypassing model level validation if you want to purposefully
|
* This allows bypassing model level validation if you want to purposefully
|
||||||
* create an asset in an invalid state. Validation is turned back on
|
* create an asset in an invalid state. Validation is turned back on
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
|
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Asset;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
|
use App\Models\Consumable;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
|
use App\Models\User;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
|
|
||||||
|
@ -97,5 +102,16 @@ class ComponentFactory extends Factory
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkedOutToAsset(Asset $asset = null)
|
||||||
|
{
|
||||||
|
return $this->afterCreating(function (Component $component) use ($asset) {
|
||||||
|
$component->assets()->attach($component->id, [
|
||||||
|
'component_id' => $component->id,
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'user_id' => 1,
|
||||||
|
'asset_id' => $asset->id ?? Asset::factory()->create()->id,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,13 @@ class LocationFactory extends Factory
|
||||||
'image' => rand(1, 9).'.jpg',
|
'image' => rand(1, 9).'.jpg',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// one of these can eventuall go away - left temporarily for conflict resolution
|
||||||
|
public function deleted(): self
|
||||||
|
{
|
||||||
|
return $this->state(['deleted_at' => $this->faker->dateTime()]);
|
||||||
|
}
|
||||||
|
|
||||||
public function deletedLocation()
|
public function deletedLocation()
|
||||||
{
|
{
|
||||||
return $this->state(function () {
|
return $this->state(function () {
|
||||||
|
|
|
@ -314,4 +314,9 @@ class UserFactory extends Factory
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleted(): self
|
||||||
|
{
|
||||||
|
return $this->state(['deleted_at' => $this->faker->dateTime()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use App\Models\Setting;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Setting::where('locale', 'no-NO')->update(['locale' => 'nb-NO']);
|
||||||
|
User::where('locale', 'no-NO')->update(['locale' => 'nb-NO']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use App\Models\Setting;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (Schema::hasTable('accessories_users')) {
|
||||||
|
Schema::rename('accessories_users', 'accessories_checkout');
|
||||||
|
|
||||||
|
Schema::table('accessories_checkout', function (Blueprint $table) {
|
||||||
|
if (!Schema::hasColumn('accessories_checkout', 'assigned_type')) {
|
||||||
|
$table->string('assigned_type')->nullable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::update('update '.DB::getTablePrefix().'accessories_checkout set assigned_type = \'App\\\\Models\\\\User\' where assigned_type is null', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if (Schema::hasTable('accessories_checkout')) {
|
||||||
|
Schema::table('accessories_checkout', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('assigned_type');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::rename('accessories_checkout', 'accessories_users');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('shortcuts_enabled')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('shortcuts_enabled');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -16,7 +16,7 @@ class AccessorySeeder extends Seeder
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
Accessory::truncate();
|
Accessory::truncate();
|
||||||
DB::table('accessories_users')->truncate();
|
DB::table('accessories_checkout')->truncate();
|
||||||
|
|
||||||
if (! Location::count()) {
|
if (! Location::count()) {
|
||||||
$this->call(LocationSeeder::class);
|
$this->call(LocationSeeder::class);
|
||||||
|
|
|
@ -36,6 +36,7 @@ class SettingsSeeder extends Seeder
|
||||||
$settings->version_footer = 'on';
|
$settings->version_footer = 'on';
|
||||||
$settings->support_footer = 'on';
|
$settings->support_footer = 'on';
|
||||||
$settings->pwd_secure_min = '8';
|
$settings->pwd_secure_min = '8';
|
||||||
|
$settings->default_avatar = 'default.png';
|
||||||
$settings->save();
|
$settings->save();
|
||||||
|
|
||||||
if ($user = User::where('username', '=', 'admin')->first()) {
|
if ($user = User::where('username', '=', 'admin')->first()) {
|
||||||
|
|
|
@ -39,6 +39,14 @@ chown -R apache:root /var/lib/snipeit/data/*
|
||||||
chown -R apache:root /var/lib/snipeit/dumps
|
chown -R apache:root /var/lib/snipeit/dumps
|
||||||
chown -R apache:root /var/lib/snipeit/keys
|
chown -R apache:root /var/lib/snipeit/keys
|
||||||
|
|
||||||
|
# Fix php settings
|
||||||
|
if [ ! -z "${PHP_UPLOAD_LIMIT}" ]
|
||||||
|
then
|
||||||
|
echo "Changing upload limit to ${PHP_UPLOAD_LIMIT}"
|
||||||
|
sed -i "s/^upload_max_filesize.*/upload_max_filesize = ${PHP_UPLOAD_LIMIT}M/" /etc/php*/php.ini
|
||||||
|
sed -i "s/^post_max_size.*/post_max_size = ${PHP_UPLOAD_LIMIT}M/" /etc/php*/php.ini
|
||||||
|
fi
|
||||||
|
|
||||||
# If the Oauth DB files are not present copy the vendor files over to the db migrations
|
# If the Oauth DB files are not present copy the vendor files over to the db migrations
|
||||||
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
|
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
|
||||||
then
|
then
|
||||||
|
|
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -15,7 +15,7 @@
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-less": "^3.3.8",
|
"bootstrap-less": "^3.3.8",
|
||||||
"bootstrap-table": "1.22.5",
|
"bootstrap-table": "1.23.0",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"css-loader": "^5.0.0",
|
"css-loader": "^5.0.0",
|
||||||
|
@ -3692,9 +3692,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/bootstrap-table": {
|
"node_modules/bootstrap-table": {
|
||||||
"version": "1.22.5",
|
"version": "1.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.0.tgz",
|
||||||
"integrity": "sha512-iaQBfZzNuMRVughNYdonPGvgL6A7xfsruqYKaSuDuUWqQDTt8WvTBVwV61XiDv2aks7RaAQoZhoi2jo9nF6U7w==",
|
"integrity": "sha512-fAIhu2CAqMsZWkzeFxXyh0yQA2DMBdB0tCdr1iF6bKr3c/Hf79cw5PykNt7NdtqLz/a0p192S8EKyT5lG4yrpw==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"jquery": "3"
|
"jquery": "3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-less": "^3.3.8",
|
"bootstrap-less": "^3.3.8",
|
||||||
"bootstrap-table": "1.22.5",
|
"bootstrap-table": "1.23.0",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"css-loader": "^5.0.0",
|
"css-loader": "^5.0.0",
|
||||||
|
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue