Compare commits

...

113 Commits

Author SHA1 Message Date
snipe db76090e10 Missed one 2019-05-28 19:12:53 -07:00
snipe 03cf3b5431 Bumped release again :( 2019-05-28 19:12:42 -07:00
snipe 40f101d471 Merge branch 'master' of https://github.com/snipe/snipe-it 2019-05-28 19:08:39 -07:00
snipe 7aa6ef5f6c Bumped version 2019-05-28 19:08:35 -07:00
Kasey 186b94751d Dockerfile update to bring us up to php v7.1 for Laravel 5.5 (#7084)
* bump up to php7.1

& change deprecated MAINTAINER to a LABEL so it is visible with `docker inspect`

* AND modapache ><

* 2 updates required to get software-properties+ppa
2019-05-28 16:58:32 -07:00
snipe 6f2717a876 Updated branch in version file 2019-05-28 13:22:59 -07:00
snipe a014af4c47 Fixed #7083 - Removed user_exists constraint on department save
If the user has been deleted, this prevented the department from being successfully saved on edit
2019-05-28 13:18:31 -07:00
snipe 2dd31544fe Increased image size to 800px, added lightboxes 2019-05-24 19:11:08 -07:00
snipe 237acdcff0 Show accessory image on view page 2019-05-24 18:22:57 -07:00
snipe 5db7a7c196 More Atlassian clarifications 2019-05-24 18:10:19 -07:00
snipe 68acdff11b Added link to Atlassian plugin 2019-05-24 18:08:40 -07:00
snipe 58e72e5ee6 Derp - typo 2019-05-24 18:06:15 -07:00
snipe 6b43cd10ba Updated README 2019-05-24 18:05:28 -07:00
snipe b2c9a38db8 Fixed casing in sync command 2019-05-24 16:12:43 -07:00
snipe 6dcdb5abae Only display the file if the log record can be found 2019-05-24 16:06:52 -07:00
snipe 56576d9e45 Fixed more camel-casing -> snake-casing 2019-05-24 16:01:12 -07:00
snipe d5c3ee5ed0 Only try to get fieldset if model is valid 2019-05-24 15:44:54 -07:00
snipe 18db0a50f1 Only gtry to delete the file if a record is found in the log 2019-05-24 15:44:40 -07:00
snipe d596ced0a0 Fixed free_seats_count variable name
(I forgot that Laravel switched camel case to snake case for their old 5.4 withCount variables)
2019-05-24 15:44:18 -07:00
snipe 78fb2b2239 Only build the log upload destination path if there is a matching record
Fixes [ch1232]
2019-05-24 15:28:53 -07:00
snipe 1472e9d5b5 Check for valid model before attempting to access fieldsets
Fixes [ch1249]
2019-05-24 15:03:15 -07:00
snipe fcbc7e4540 Fixed Undefined variable user in $backto if checked out to a non-user
Fixes [ch9194]
2019-05-24 14:51:27 -07:00
snipe 93bf541ce7 Fixed missed consumables_count withCount() statement 2019-05-24 14:21:53 -07:00
snipe 0e48d7b080 Removed alert-danger from tests 2019-05-24 14:21:37 -07:00
snipe 1e6c85da41 Removed custom fields from AssignedSearch to prevent confusing data in selectlist
Fixes [ch9193]
2019-05-24 13:50:11 -07:00
snipe c5a23e8f5e Fixed bug where sorting by company name in Users API did not work
Fixes [ch9200]
2019-05-24 13:37:20 -07:00
snipe b6d2392303 Small fix for reordering fields
Fixes Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'order' cannot be null (SQL: insert into `custom_field_custom_fieldset` (`custom_field_id`, `custom_fieldset_id`, `order`, `required`) values (12, 7, , 0)) [ch1151]

This needs revisiting for a more solid fix, especially for data that was already entered bad.
2019-05-24 12:05:52 -07:00
snipe 9995f1a743 Fixed field mapping 2019-05-24 11:45:07 -07:00
snipe d6f251e992 Updated importer to work with newer CSV Reader::getRecords() method 2019-05-24 11:44:57 -07:00
snipe 4be95eac4b Removed extra escaping on checkin 2019-05-24 11:44:39 -07:00
snipe 8914d14681 Tidied up license check 2019-05-24 05:26:52 -07:00
snipe d4725b61be Check that a model exists before trying to fiddle with fieldsets 2019-05-24 04:48:04 -07:00
snipe aa0b627fe7 Fixed missing asset validation 2019-05-24 04:47:35 -07:00
snipe 5be5e3271d Trying to fix ajax asset validation
This I think gets us closer, but still not handling the validation on the asset properly.

When I do a print_r of the validation in the other items, its looking for an error bag that looks something like this:

```
Illuminate\Support\MessageBag Object
(
    [messages:protected] => Array
        (
            [name] => Array
                (
                    [0] => The name field is required.
                )

            [seats] => Array
                (
                    [0] => The seats field is required.
                )

            [category_id] => Array
                (
                    [0] => The category id field is required.
                )

        )

    [format:protected] => :message
)
```

Currently the Assets ajax returns:

```
[2019-05-24 06:52:06] develop.ERROR: array (
  'messages' =>
  array (
    'model_id' =>
    array (
      0 => 'The model id field is required.',
    ),
    'status_id' =>
    array (
      0 => 'The status id field is required.',
    ),
    'asset_tag' =>
    array (
      0 => 'The asset tag field is required.',
    ),
  ),
)
```

So not sure why it’s not working.
2019-05-24 03:55:31 -07:00
snipe dd5d5cc07c Handle JSON validation errors like 5.4 2019-05-24 01:12:38 -07:00
snipe 84c3709161 Handle JSON validation errors like 5.4 2019-05-24 01:12:21 -07:00
snipe 96e2d74ae3 Handle JSON validation errors like 5.4 2019-05-24 00:46:30 -07:00
snipe bf93e8cc32 Use getReader instead of fetchAssoc for CSV parser
https://csv.thephpleague.com/9.0/upgrading/
2019-05-23 19:09:58 -07:00
snipe d1a8955ef9 Bumped packages 2019-05-23 19:09:14 -07:00
snipe 149ac4bdf8 Removed cosole log 2019-05-23 17:52:53 -07:00
snipe 2d036c64e9 Change ->has() to ->filled() 2019-05-23 17:39:50 -07:00
snipe 8db2470ac4 Switch has() to filled() 2019-05-23 17:17:46 -07:00
snipe 79156ff8f4 Bumped version 2019-05-23 17:10:47 -07:00
snipe 8e86d780bf Fix for included files in backup 2019-05-23 17:08:51 -07:00
snipe f6ef139111 Fixed baseUrl is undefined error
I literally cannot figure out how this ever worked before.
2019-05-23 16:56:22 -07:00
snipe 12ec2d1f7a Fixed custom field edit screen 2019-05-22 01:07:14 -07:00
snipe 0dfc28b0e8 Bumped laravel version in readme 2019-05-22 01:04:42 -07:00
snipe b3132a4a8f Updated travis with new php versions 2019-05-22 01:03:11 -07:00
snipe 6cd25fbdeb Updated backup path in backup admin 2019-05-22 00:56:14 -07:00
snipe 4be8ba9f17 Updated withCount to use manual naming 2019-05-22 00:52:51 -07:00
snipe df8008f1ed Renamed fire() to handle() 2019-05-22 00:52:32 -07:00
snipe 77547c528b Added the command loader to console kernel 2019-05-22 00:52:14 -07:00
snipe bfb910f375 Set the serialization 2019-05-22 00:51:43 -07:00
snipe 57e80ee317 Removed old laravel backups config
This config file was renamed in a newer version of spatie laravel-backup
2019-05-22 00:51:33 -07:00
snipe de1189295a Added spatie language files 2019-05-22 00:51:00 -07:00
snipe 20d0dce73e Use laravel v5.5 withCount manual aliases 2019-05-22 00:50:48 -07:00
snipe 144a32b1ca Removed debugbar service provider (autodiscovery) 2019-05-22 00:50:00 -07:00
snipe 8244a2ad23 New backups config for spatie 2019-05-22 00:49:38 -07:00
snipe 77c3b8f8c1 Updated packages 2019-05-22 00:07:49 -07:00
snipe 7b34cf1a31 Bumped version 2019-05-21 19:17:56 -07:00
snipe 21ec670531 Updated language strings 2019-05-21 19:17:00 -07:00
snipe b2eacb147b Fixed #7046 - added user website url back into UI 2019-05-21 18:55:12 -07:00
snipe 729e3eb70d Updated email strings 2019-05-21 18:43:00 -07:00
snipe 978533b2f4 Fixed XSS vulnerability when creating a new categories, etc via modal on create
Same fix as before, because of the weird select2 post-parsing ajax behavior
2019-05-21 18:29:50 -07:00
snipe 0358d13ddb Fixed #7044 - API update deleted custom fields if they are not re-presented 2019-05-20 11:49:18 -07:00
snipe c944304444 Updated packages
- Updating erusev/parsedown (v1.7.2 => 1.7.3): Downloading (100%)
  - Updating squizlabs/php_codesniffer (3.4.1 => 3.4.2): Downloading (100%)
  - Updating symfony/polyfill-mbstring (v1.10.0 => v1.11.0): Downloading (100%)
  - Updating symfony/var-dumper (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating league/flysystem (1.0.50 => 1.0.51): Downloading (100%)
  - Updating symfony/translation (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating nesbot/carbon (1.36.2 => 1.37.1): Downloading (100%)
  - Updating symfony/debug (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/console (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/finder (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/polyfill-ctype (v1.10.0 => v1.11.0): Downloading (100%)
  - Updating symfony/polyfill-php70 (v1.10.0 => v1.11.0): Downloading (100%)
  - Updating symfony/http-foundation (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/event-dispatcher (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/http-kernel (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/process (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/routing (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/polyfill-util (v1.10.0 => v1.11.0): Downloading (100%)
  - Updating symfony/polyfill-php56 (v1.10.0 => v1.11.0): Downloading (100%)
  - Updating symfony/psr-http-message-bridge (v1.1.1 => v1.1.2): Downloading (failed)
Downloading (100%)
  - Updating rollbar/rollbar (v1.7.5 => v1.8.1): Downloading (100%)
  - Updating symfony/yaml (v3.4.23 => v3.4.27): Downloading (100%)
  - Updating symfony/browser-kit (v3.4.23 => v3.4.27): Downloading (100%)
2019-05-20 10:10:46 -07:00
Bob Clough 096393389c Fixes #5054: LDAP users deactivated for none-ad (#7032)
When using none-AD ldap, users are automatically deactivated every LDAP
sync.  This commit changes the behaviour so that if the active flag isn't set,
the users are enabled.

Fixed #5054, at least for 4.X
2019-05-16 09:31:55 -07:00
snipe 9eb7b668d1 Fixed #6880 - correctly encrypt encrypted fields via the API 2019-05-15 19:33:30 -07:00
snipe 6728089106 Fixed #6883 - remove escaping of fields on LDAP import 2019-05-15 19:15:41 -07:00
snipe 33b59d7bed Bumped version 2019-05-15 16:45:07 -07:00
snipe 888bdbdb68 Added ability to update groups via API
Fixes [ch9139]
2019-05-15 16:39:34 -07:00
snipe d67c931f6a Import locations from CSV via command line (#7021)
* Added import locations command

* Small fixes to location importer

* Added country, LDAP OU

* Cleaned up comments, added more clarification to what the script does
2019-05-13 02:27:19 -07:00
snipe dbdc511eff Merge branch 'master' of https://github.com/snipe/snipe-it 2019-05-08 09:23:58 -04:00
snipe f47b960566 Added API middleware to API routes to enable throttling
TODO: Figure out how to make this costumizable without touching the code
2019-05-08 09:23:54 -04:00
snipe d016076806 Fixed #6956 - viewKeys policy inconsistent (#7009)
* Fixed #6956 - Added additional gates show showing/hiding license keys

* Modified gate to allow user to see licenses if they can create or edit the license as well
2019-05-08 08:14:49 -04:00
snipe 23fa5d0bf4 Fixed #7003 - crash when warranty months or purchase date is null 2019-05-07 15:33:57 -04:00
Joris van Eijden 486c708911 Leave the activated state for users alone in normal LDAP synchronisation. (#6988) 2019-05-06 09:40:53 -04:00
snipe e5c2d77c7d Fixes #6204 - added email alerts and web/API access to assets due for audits (#6992)
* Added upcoming audit report

TODO: Fid diff/threshold math

* Added route to list overdue / upcoming assets via API

* Controller/API methods for due/overdue audits

We could probably skip this and just handle it via view in the routes…

* Added query scopes for due and overdue audits

* Added audit due console command to kernel

* Added ability to pass audit specs to main API asset search method

* Added audit presenter

* Added bootstrap-tables presenter formatter to display an audit button

* Added gated sidenav items to left nav

* Added audit due/overdue blades

* Cleanup on audit due/overdue console command

* Added language strings for audit views

* Fixed :threshold placeholder

* Removed unused setting variable

* Fixed next audit date math

* Added scope for both overdue and upcoming

* Derp. Wrong version

* Bumped version

(I will release this version officially tomorrow)
2019-05-05 22:32:52 -04:00
snipe ce16eae508 Merge branch 'master' of https://github.com/snipe/snipe-it 2019-05-02 15:20:52 -07:00
snipe dc73dbfbfd Fixed #6911 - note must be a string on license checkin 2019-05-02 15:20:47 -07:00
snipe dae26e0378 Remove “Imported from LDAP” note override 2019-04-18 17:56:08 -04:00
snipe 1bb1f7342f Fixed #6922 - date_add crashing if EOL is null 2019-04-18 15:49:59 -04:00
snipe 420e8bc85a Allow phone number to be changed in Profile 2019-04-18 14:13:50 -04:00
snipe a521523d45 Truncate imports table on seed 2019-04-18 14:13:33 -04:00
snipe 25884a893e Bumped version 2019-03-20 02:41:33 -07:00
snipe d1e9fbfa24 Updated compoer 2019-03-20 02:37:44 -07:00
snipe da015ec4a8 Fixed #6834 and #6402 - use inline QR code generation for 2FA (#6840)
* Fixed  #6834 and #6402 - use inline QR code generation for

* Update auth controllers to use translations

* Updated composer lock

* Added comments

* Moar comments

* Typo
2019-03-20 01:24:31 -07:00
snipe 1451b4f45d Merge branch 'master' of https://github.com/snipe/snipe-it 2019-03-18 20:51:11 -07:00
snipe b6da68a69c Bumped version 2019-03-18 20:50:47 -07:00
snipe dee92cfc6c Fixes XSS vulnerabilities (#6831)
* Properly escape log_meta values

* Vue syntax fix to allow npm run dev to work again

* Janky fix for Select2 bug

* Compiled production assets

* Escape user’s last name in API

* Removed duplicate alertClass

* Compiled production assets
2019-03-18 20:49:32 -07:00
snipe dec77890bd Merge branch 'master' of https://github.com/snipe/snipe-it 2019-03-18 11:59:48 -07:00
snipe 0e1289f12f Fixes #6821 - fixed 2 fa active for users list (#6822)
* Fixed #6821 - confusing UI for 2FA when 2FA is universally enforced

I also updated the language in the user’s listing table to clarify what “activated” means

* Added login enabled info to user view

* Clarified comments

* Added info about 2FA on user profile

Because why not

* Added nowrap to table, and added 2FA reset for superadmins
2019-03-18 11:59:02 -07:00
snipe 7b33f95e83 Fixes/import permissions mask (#6826)
* Check for empty headers in import

* Added import permission

* Fixed model path in docblock

* Added import gate to default blade

* Check if the user is an admin OR idf they have import permissions

* Walked back that admin permission

Since admins are bound by full company support, it makes less sense to let admins have this permission by default, versus having them specifically designated to the import permission
2019-03-18 11:58:08 -07:00
snipe ab6744dfba Merge branch 'master' of https://github.com/snipe/snipe-it 2019-03-14 15:38:20 -07:00
snipe 0fd940ffa4 Check for empty headers in import 2019-03-14 15:38:07 -07:00
Tim Farmer 5893e25b43 Label bugs in alerts settings (#6808)
* Label bugs in alerts settings

Found another label bug where the alert_email label should be alerts_enabled.

* Update alerts.blade.php
2019-03-14 10:53:05 -07:00
snipe 7c3bbe3097 Fixes #6776 hungary date format (#6823)
* Add @timothyfarmer as a contributor

* Fixed #6776 - added hungary time format
2019-03-13 19:39:38 -07:00
snipe 858d382e26 Changed logging to info level for LDAP 2019-03-13 15:14:03 -07:00
snipe de16fee00a Change image unlink error log to info from error 2019-03-13 12:22:12 -07:00
Tim Farmer 7deab0f53b Label bugs in general settings (#6801)
* checkbox label bug

The checkbox label in general settings for require_accept_signature was set to full_multiple_companies_support instead so when you click the label for require accept signature it would check the wrong box.

* Update general.blade.php

* Update general.blade.php

Another label that is wrong in general settings
2019-03-08 12:24:24 -08:00
Jonathon Reinhart e59ec8b27f Run Laravel schedule in docker image using supervisord (#6606)
* docker: Rename /entrypoint.sh to /startup.sh

This script is not configured as the docker image ENTRYPOINT, thus it is
misleading to name it so.

* docker: Terminate supervisord if a process enters the FATAL state

By terminating PID 1, this will also terminate the Docker container.

* docker: Use supervisord to start up apache and cron

Note that this uses `apache2ctl -DFOREGROUND` rather than manually
sourcing /etc/apache2/envvars and running apache2, as recommended at
https://advancedweb.hu/2018/07/03/supervisor_docker/.

* docker: Add artisan schedule:run to crontab

This also switches to executing /var/www/html/artisan directly.

* docker: Run artisan schedule:run directly from supervisor

This has the following benefits over using cron:
- Cron doesn't need to be installed
- Docker-provided environment variables are preserved
- It's easy and explicit to run as the docker user
2019-03-07 12:42:00 -08:00
snipe 6d98bd6846 Fixed error if item requested or request was deleted (#6786)
ch628
2019-03-05 23:47:36 -08:00
snipe 58768e5aee Added ability to search consumables by item number (#6785)
Fixes ch1086
2019-03-05 23:21:22 -08:00
snipe 28a450ea25 Added ability to do full name search in user dropdown selectlist (#6784) 2019-03-05 21:13:39 -08:00
snipe 1393f44070 Create FUNDING.yml 2019-03-04 23:57:17 -08:00
snipe 8016939f31 Merge branch 'master' of https://github.com/snipe/snipe-it 2019-03-01 17:39:55 -08:00
snipe c1ad2f9376 Added link to Marksman - A Windows agent for Snipe-IT
Per https://github.com/Scope-IT/marksman/issues/9#issuecomment-468275142
2019-03-01 17:39:50 -08:00
snipe 9575cd2651 Add accessories endpoint to user API (#6775) 2019-03-01 17:21:03 -08:00
snipe cf086b711e Merge branch 'master' of https://github.com/snipe/snipe-it 2019-02-22 13:24:58 -08:00
snipe 53db96edad Bumped minor version 2019-02-22 13:24:45 -08:00
snipe 3b62c4a83a Fixes/integrity constraint (#6754)
* Migration to fix nullables

This should fix an issue introduced in 90cddb7aee where we’re passing null instead of an empty string (necessary to nullify values via the API)

* Removed asset migration - serial was already fixed
2019-02-22 13:20:42 -08:00
snipe 5f3147cf36 Added support for enum that was added :( 2019-02-20 21:04:03 -08:00
snipe 738896bdc2 Make serial nullable
Guessing this is new due to later versions of mysql
2019-02-20 20:47:14 -08:00
274 changed files with 14163 additions and 2226 deletions
+9
View File
@@ -1650,6 +1650,15 @@
"contributions": [
"code"
]
},
{
"login": "timothyfarmer",
"name": "Tim Farmer",
"avatar_url": "https://avatars1.githubusercontent.com/u/7632599?v=4",
"profile": "https://github.com/timothyfarmer",
"contributions": [
"code"
]
}
]
}
+5
View File
@@ -0,0 +1,5 @@
# You can add one username per supported platform and one custom link
# patreon: # Replace with your Patreon username
# open_collective: # Replace with your Open Collective username
# ko_fi: # Replace with your Ko-fi username
custom: https://snipeitapp.com/donate
+1 -3
View File
@@ -14,9 +14,7 @@ services:
# list any PHP version you want to test against
php:
- 5.6
- 7.0
- 7.1
- 7.1.2
- 7.2
- 7.3
+23 -25
View File
@@ -1,26 +1,27 @@
FROM ubuntu:xenial
MAINTAINER Brady Wetherington <uberbrady@gmail.com>
LABEL maintainer="uberbrady, hinchk"
RUN apt-get update && apt-get install -y software-properties-common
RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php
RUN apt-get update && apt-get install -y \
apache2 \
apache2-bin \
libapache2-mod-php7.0 \
php7.0-curl \
php7.0-ldap \
php7.0-mysql \
php7.0-mcrypt \
php7.0-gd \
php7.0-xml \
php7.0-mbstring \
php7.0-zip \
php7.0-bcmath \
libapache2-mod-php7.1 \
php7.1-curl \
php7.1-ldap \
php7.1-mysql \
php7.1-mcrypt \
php7.1-gd \
php7.1-xml \
php7.1-mbstring \
php7.1-zip \
php7.1-bcmath \
patch \
curl \
vim \
git \
cron \
mysql-client \
cron \
supervisor \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -28,8 +29,8 @@ RUN phpenmod mcrypt
RUN phpenmod gd
RUN phpenmod bcmath
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.0/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.0/cli/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.1/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.1/cli/php.ini
RUN useradd -m --uid 1000 --gid 50 docker
@@ -69,7 +70,9 @@ RUN \
&& rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \
&& mkdir "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \
&& ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \
&& chown docker "/var/lib/snipeit/keys/"
&& chown docker "/var/lib/snipeit/keys/" \
&& chmod +x /var/www/html/artisan \
&& echo "Finished setting up application in /var/www/html"
############## DEPENDENCIES via COMPOSER ###################
@@ -96,16 +99,11 @@ VOLUME ["/var/lib/snipeit"]
##### START SERVER
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
COPY docker/startup.sh docker/supervisord.conf /
COPY docker/supervisor-exit-event-listener /usr/bin/supervisor-exit-event-listener
RUN chmod +x /startup.sh /usr/bin/supervisor-exit-event-listener
# Add Tini
ENV TINI_VERSION v0.14.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
CMD ["/entrypoint.sh"]
CMD ["/startup.sh"]
EXPOSE 80
EXPOSE 443
+13 -11
View File
@@ -1,14 +1,14 @@
[![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-180-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it)
[![All Contributors](https://img.shields.io/badge/all_contributors-181-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it)
## Snipe-IT - Open Source Asset Management System
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
It is built on [Laravel 5.4](http://laravel.com).
It is built on [Laravel 5.5](http://laravel.com).
Snipe-IT is actively developed and we're [releasing quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
__This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
@@ -58,12 +58,20 @@ Since the release of the JSON REST API, several third-party developers have been
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
- [InQRy](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
- [jamf2snipe](https://github.com/ParadoxGuitarist/jamf2snipe) by [@ParadoxGuitarist](https://github.com/ParadoxGuitarist) - Python script to sync assets between a JAMFPro instance and a Snipe-II instance
- [jamf2snipe](https://github.com/ParadoxGuitarist/jamf2snipe) by [@ParadoxGuitarist](https://github.com/ParadoxGuitarist) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
- [Marksman](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
- [Snipe-IT plugin for Jira Service Desk (beta)](https://marketplace.atlassian.com/apps/1220379/snipe-it-for-jira-service-desk-beta?hosting=cloud&tab=overview) - for the upcoming Snipe-IT v5 only
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
-----
### Security
To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.
-----
### Contributors
Thanks goes to all of these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)) who have helped Snipe-IT get this far:
@@ -95,7 +103,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars2.githubusercontent.com/u/982885?v=4" width="110px;"/><br /><sub>Martin Stub</sub>](http://martinstub.dk)<br />[🌍](#translation-stubben "Translation") | [<img src="https://avatars2.githubusercontent.com/u/28959963?v=4" width="110px;"/><br /><sub>Meyer Flavio</sub>](https://github.com/meyerf99)<br />[🌍](#translation-meyerf99 "Translation") | [<img src="https://avatars3.githubusercontent.com/u/796443?v=4" width="110px;"/><br /><sub>Micael Rodrigues</sub>](https://github.com/MicaelRodrigues)<br />[🌍](#translation-MicaelRodrigues "Translation") | [<img src="https://avatars0.githubusercontent.com/u/10481331?v=4" width="110px;"/><br /><sub>Mikael Rasmussen</sub>](http://rubixy.com/)<br />[🌍](#translation-mikaelssen "Translation") | [<img src="https://avatars1.githubusercontent.com/u/1544552?v=4" width="110px;"/><br /><sub>IxFail</sub>](https://github.com/IxFail)<br />[🌍](#translation-IxFail "Translation") | [<img src="https://avatars3.githubusercontent.com/u/18483118?v=4" width="110px;"/><br /><sub>Mohammed Fota</sub>](http://www.mohammedfota.com)<br />[🌍](#translation-MohammedFota "Translation") | [<img src="https://avatars0.githubusercontent.com/u/227080?v=4" width="110px;"/><br /><sub>Moayad Alserihi</sub>](https://github.com/omego)<br />[🌍](#translation-omego "Translation") |
| [<img src="https://avatars0.githubusercontent.com/u/1680266?v=4" width="110px;"/><br /><sub>saymd</sub>](https://github.com/saymd)<br />[🌍](#translation-saymd "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1826808?v=4" width="110px;"/><br /><sub>Patrik Larsson</sub>](https://nordsken.se)<br />[🌍](#translation-pooot "Translation") | [<img src="https://avatars1.githubusercontent.com/u/20584746?v=4" width="110px;"/><br /><sub>drcryo</sub>](https://github.com/drcryo)<br />[🌍](#translation-drcryo "Translation") | [<img src="https://avatars1.githubusercontent.com/u/19408004?v=4" width="110px;"/><br /><sub>pawel1615</sub>](https://github.com/pawel1615)<br />[🌍](#translation-pawel1615 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/23340468?v=4" width="110px;"/><br /><sub>bodrovics</sub>](https://github.com/bodrovics)<br />[🌍](#translation-bodrovics "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3257654?v=4" width="110px;"/><br /><sub>priatna</sub>](https://github.com/priatna)<br />[🌍](#translation-priatna "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5358374?v=4" width="110px;"/><br /><sub>Fan Jiang</sub>](https://amayume.net)<br />[🌍](#translation-ProfFan "Translation") |
| [<img src="https://avatars1.githubusercontent.com/u/22555451?v=4" width="110px;"/><br /><sub>ragnarcx</sub>](https://github.com/ragnarcx)<br />[🌍](#translation-ragnarcx "Translation") | [<img src="https://avatars2.githubusercontent.com/u/18654582?v=4" width="110px;"/><br /><sub>Rein van Haaren</sub>](http://www.reinvanhaaren.nl/)<br />[🌍](#translation-reinvanhaaren "Translation") | [<img src="https://avatars1.githubusercontent.com/u/386672?v=4" width="110px;"/><br /><sub>Teguh Dwicaksana</sub>](http://dheche.songolimo.net)<br />[🌍](#translation-dheche "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2572552?v=4" width="110px;"/><br /><sub>fraccie</sub>](https://github.com/FRaccie)<br />[🌍](#translation-FRaccie "Translation") | [<img src="https://avatars0.githubusercontent.com/u/35182720?v=4" width="110px;"/><br /><sub>vinzruzell</sub>](https://github.com/vinzruzell)<br />[🌍](#translation-vinzruzell "Translation") | [<img src="https://avatars1.githubusercontent.com/u/7883603?v=4" width="110px;"/><br /><sub>Kevin Austin</sub>](http://kevinaustin.com)<br />[🌍](#translation-vipsystem "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3861828?v=4" width="110px;"/><br /><sub>Wira Sandy</sub>](http://azuraweb.xyz)<br />[🌍](#translation-wira-sandy "Translation") |
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") |
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -108,9 +116,3 @@ Please see the documentation on [contributing and developing for Snipe-IT](https
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
-----
### Security
To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use League\Csv\Reader;
use App\Models\Location;
class ImportLocations extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:import-locations {filename}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import locations and their parents';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (!ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$filename = $this->argument('filename');
$csv = Reader::createFromPath(storage_path('private_uploads/imports/').$filename, 'r');
$this->info('Attempting to process: '.storage_path('private_uploads/imports/').$filename);
$csv->setOffset(1); //because we don't want to insert the header
$results = $csv->getRecords();
// Import parent location names first if they don't exist
foreach ($results as $parent_index => $parent_row) {
$parent_name = trim($parent_row['Parent Name']);
// First create any parents if they don't exist
if ($parent_name!='') {
// Save parent location name
// This creates a sort of name-stub that we'll update later on in this script
$parent_location = Location::firstOrCreate(array('name' => $parent_name));
$this->info('Parent for '.$parent_row['Name'].' is '.$parent_name.'. Attempting to save '.$parent_name.'.');
// Check if the record was updated or created.
// This is mostly for clearer debugging.
if ($parent_location->exists) {
$this->info('- Parent location '.$parent_name.' already exists.');
} else {
$this->info('- Parent location '.$parent_name.' was created.');
}
} else {
$this->info('- No parent location for '.$parent_row['Name'].' provided.');
}
}
// Loop through ALL records and add/update them if there are additional fields
// besides name
foreach ($results as $index => $row) {
// Set the location attributes to save
$location = Location::firstOrNew(array('name' => trim($row['Name'])));
$location->name = trim($row['Name']);
$location->currency = trim($row['Currency']);
$location->address = trim($row['Address 1']);
$location->address2 = trim($row['Address 2']);
$location->city = trim($row['City']);
$location->state = trim($row['State']);
$location->zip = trim($row['Zip']);
$location->country = trim($row['Country']);
$location->ldap_ou = trim($row['OU']);
$this->info('Checking location: '.$location->name);
// If a parent name nis provided, we created it earlier in the script,
// so let's grab that ID
if ($parent_name) {
$parent = Location::where('name', '=', $parent_name)->first();
$location->parent_id = $parent->id;
$this->info('Parent ID: '.$parent->id);
}
// Make sure the more advanced (non-name) fields pass validation
if (($location->isValid()) && ($location->save())) {
// Check if the record was updated or created.
// This is mostly for clearer debugging.
if ($location->exists) {
$this->info('Location ' . $location->name . ' already exists. Updating...');
} else {
$this->info('- Location '.$location->name.' was created. ');
}
// If there's a validation error, display that
} else {
$this->error('- Non-parent Location '.$location->name.' could not be created: '.$location->getErrors() );
}
}
}
}
+28 -27
View File
@@ -61,16 +61,16 @@ class LdapSync extends Command
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$this->info(json_encode($json_summary));
}
LOG::error($e);
LOG::info($e);
return [];
}
$summary = array();
try {
try {
if ($this->option('base_dn') != '') {
$search_base = $this->option('base_dn');
LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
} else {
$search_base = null;
}
@@ -80,7 +80,7 @@ class LdapSync extends Command
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$this->info(json_encode($json_summary));
}
LOG::error($e);
LOG::info($e);
return [];
}
@@ -106,7 +106,7 @@ class LdapSync extends Command
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
$ldap_ou_lengths = array();
foreach ($ldap_ou_locations as $location) {
$ldap_ou_lengths[] = strlen($location["ldap_ou"]);
}
@@ -168,34 +168,36 @@ class LdapSync extends Command
$item["ldap_location_override"] = isset($results[$i]["ldap_location_override"]) ? $results[$i]["ldap_location_override"]:"";
$item["location_id"] = isset($results[$i]["location_id"]) ? $results[$i]["location_id"]:"";
// This is active directory, not regular LDAP
if ( array_key_exists('useraccountcontrol', $results[$i]) ) {
$enabled_accounts = [
'512', '544', '66048', '66080', '262656', '262688', '328192', '328224'
];
$item['activated'] = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
// Fall through to LDAP
$user = User::where('username', $item["username"])->first();
if ($user) {
// Updating an existing user.
$item["createorupdate"] = 'updated';
} else {
$item['activated'] = 0;
}
// User exists
$item["createorupdate"] = 'updated';
if (!$user = User::where('username', $item["username"])->first()) {
// Creating a new user.
$user = new User;
$user->password = $pass;
$user->activated = 0;
$item["createorupdate"] = 'created';
}
// Create the user if they don't exist.
$user->first_name = e($item["firstname"]);
$user->last_name = e($item["lastname"]);
$user->username = e($item["username"]);
$user->email = e($item["email"]);
$user->first_name = $item["firstname"];
$user->last_name = $item["lastname"];
$user->username = $item["username"];
$user->email = $item["email"];
$user->employee_num = e($item["employee_number"]);
$user->activated = $item['activated'];
// Sync activated state for Active Directory.
if ( array_key_exists('useraccountcontrol', $results[$i]) ) {
$enabled_accounts = [
'512', '544', '66048', '66080', '262656', '262688', '328192', '328224'
];
$user->activated = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
}
// If we're not using AD, and there isn't an activated flag set, activate all users
elseif (empty($ldap_result_active_flag)) {
$user->activated = 1;
}
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
@@ -209,7 +211,6 @@ class LdapSync extends Command
}
$user->notes = 'Imported from LDAP';
$user->ldap_import = 1;
$errors = '';
+1 -1
View File
@@ -65,7 +65,7 @@ class ObjectImportCommand extends Command
*
* @return mixed
*/
public function fire()
public function handle()
{
$filename = $this->argument('filename');
$class = title_case($this->option('item-type'));
@@ -42,7 +42,7 @@ class SendExpectedCheckinAlerts extends Command
*
* @return mixed
*/
public function fire()
public function handle()
{
$settings = Setting::getSettings();
$whenNotify = Carbon::now()->addDays(7);
@@ -43,7 +43,7 @@ class SendExpirationAlerts extends Command
*
* @return mixed
*/
public function fire()
public function handle()
{
$settings = Setting::getSettings();
@@ -0,0 +1,91 @@
<?php
namespace App\Console\Commands;
use App\Models\Asset;
use App\Models\License;
use App\Models\Setting;
use App\Notifications\ExpiringAssetsNotification;
use App\Models\Recipients;
use DB;
use Illuminate\Console\Command;
use App\Notifications\SendUpcomingAuditNotification;
use Carbon\Carbon;
class SendUpcomingAuditReport extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:upcoming-audits';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send email/slack notifications for upcoming asset audits.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$settings = Setting::getSettings();
if (($settings->alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) {
// Send a rollup to the admin, if settings dictate
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
return new \App\Models\Recipients\AlertRecipient($item);
});
// Assets due for auditing
$assets = Asset::whereNotNull('next_audit_date')
->DueOrOverdueForAudit($settings)
->orderBy('last_audit_date', 'asc')->get();
if ($assets->count() > 0) {
$this->info(trans_choice('mail.upcoming-audits', $assets->count(),
['count' => $assets->count(), 'threshold' => $settings->audit_warning_days]));
\Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days));
$this->info('Audit report sent to '.$settings->alert_email);
} else {
$this->info('No assets to be audited. No report sent.');
}
} elseif ($settings->alert_email=='') {
$this->error('Could not send email. No alert email configured in settings');
} elseif (!$settings->audit_warning_days) {
$this->error('No audit warning days set in Admin Notifications. No mail will be sent.');
} elseif ($settings->alerts_enabled!=1) {
$this->info('Alerts are disabled in the settings. No mail will be sent');
} else {
$this->error('Something went wrong. :( ');
$this->error('Admin Notifications Email Setting: '.$settings->alert_email);
$this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days);
$this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled);
}
}
}
+1 -1
View File
@@ -39,7 +39,7 @@ class SyncAssetCounters extends Command
public function handle()
{
$start = microtime(true);
$assets = Asset::withCount('checkins', 'checkouts', 'userRequests')
$assets = Asset::withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')
->withTrashed()->get();
if ($assets) {
+1 -1
View File
@@ -64,7 +64,7 @@ class SyncAssetLocations extends Command
$output['info'][] = 'There are '.$assigned_user_assets->count().' assets checked out to users.';
foreach ($assigned_user_assets as $assigned_user_asset) {
if (($assigned_user_asset->assignedTo) && ($assigned_user_asset->assignedTo->userLoc)) {
$new_location=$assigned_user_asset->assignedTo->userloc->id;
$new_location = $assigned_user_asset->assignedTo->userLoc->id;
$output['info'][] ='Setting User Asset ' . $assigned_user_asset->id . ' ('.$assigned_user_asset->asset_tag.') to ' . $assigned_user_asset->assignedTo->userLoc->name . ' which is id: ' . $new_location;
} else {
$output['warn'][] ='Asset ' . $assigned_user_asset->id . ' ('.$assigned_user_asset->asset_tag.') still has no location! ';
+1 -1
View File
@@ -36,7 +36,7 @@ class SystemBackup extends Command
*
* @return mixed
*/
public function fire()
public function handle()
{
//
$this->call('backup:run');
+5
View File
@@ -2,6 +2,7 @@
namespace App\Console;
use App\Console\Commands\RestoreDeletedUsers;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -31,6 +32,8 @@ class Kernel extends ConsoleKernel
Commands\RegenerateAssetTags::class,
Commands\SyncAssetCounters::class,
Commands\RestoreDeletedUsers::class,
Commands\SendUpcomingAuditReport::class,
Commands\ImportLocations::class,
];
/**
@@ -47,10 +50,12 @@ class Kernel extends ConsoleKernel
$schedule->command('snipeit:expected-checkin')->daily();
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
$schedule->command('snipeit:upcoming-audits')->daily();
}
protected function commands()
{
require base_path('routes/console.php');
$this->load(__DIR__.'/Commands');
}
}
+13
View File
@@ -23,6 +23,7 @@ class Handler extends ExceptionHandler
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
\Intervention\Image\Exception\NotSupportedException::class,
];
/**
@@ -117,4 +118,16 @@ class Handler extends ExceptionHandler
return redirect()->guest('login');
}
/**
* Convert a validation exception into a JSON response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Validation\ValidationException $exception
* @return \Illuminate\Http\JsonResponse
*/
protected function invalidJson($request, ValidationException $exception)
{
return response()->json($exception->errors(), $exception->status);
}
}
+3 -3
View File
@@ -281,9 +281,9 @@ class Helper
*/
public static function checkLowInventory()
{
$consumables = Consumable::withCount('consumableAssignments')->whereNotNull('min_amt')->get();
$accessories = Accessory::withCount('users')->whereNotNull('min_amt')->get();
$components = Component::withCount('assets')->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();
$components = Component::withCount('assets as assets_count')->whereNotNull('min_amt')->get();
$avail_consumables = 0;
$items_array = array();
@@ -94,7 +94,7 @@ class AccessoriesController extends Controller
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 250, function ($constraint) {
Image::make($image->getRealPath())->resize(null, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
@@ -173,7 +173,7 @@ class AccessoriesController extends Controller
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 250, function ($constraint) {
Image::make($image->getRealPath())->resize(null, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
@@ -26,23 +26,23 @@ class AccessoriesController extends Controller
$accessories = Accessory::with('category', 'company', 'manufacturer', 'users', 'location');
if ($request->has('search')) {
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$accessories->where('company_id','=',$request->input('company_id'));
}
if ($request->has('category_id')) {
if ($request->filled('category_id')) {
$accessories->where('category_id','=',$request->input('category_id'));
}
if ($request->has('manufacturer_id')) {
if ($request->filled('manufacturer_id')) {
$accessories->where('manufacturer_id','=',$request->input('manufacturer_id'));
}
if ($request->has('supplier_id')) {
if ($request->filled('supplier_id')) {
$accessories->where('supplier_id','=',$request->input('supplier_id'));
}
@@ -40,7 +40,7 @@ class AssetMaintenancesController extends Controller
$maintenances = $maintenances->TextSearch(e($request->input('search')));
}
if ($request->has('asset_id')) {
if ($request->filled('asset_id')) {
$maintenances->where('asset_id', '=', $request->input('asset_id'));
}
@@ -48,15 +48,15 @@ class AssetModelsController extends Controller
'models.updated_at',
])
->with('category','depreciation', 'manufacturer','fieldset')
->withCount('assets');
->withCount('assets as assets_count');
if ($request->has('status')) {
if ($request->filled('status')) {
$assetmodels->onlyTrashed();
}
if ($request->has('search')) {
if ($request->filled('search')) {
$assetmodels->TextSearch($request->input('search'));
}
@@ -114,7 +114,7 @@ class AssetModelsController extends Controller
public function show($id)
{
$this->authorize('view', AssetModel::class);
$assetmodel = AssetModel::withCount('assets')->findOrFail($id);
$assetmodel = AssetModel::withCount('assets as assets_count')->findOrFail($id);
return (new AssetModelsTransformer)->transformAssetModel($assetmodel);
}
@@ -179,7 +179,7 @@ class AssetModelsController extends Controller
try {
unlink(public_path().'/uploads/models/'.$assetmodel->image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -210,7 +210,7 @@ class AssetModelsController extends Controller
$settings = \App\Models\Setting::getSettings();
if ($request->has('search')) {
if ($request->filled('search')) {
$assetmodels = $assetmodels->SearchByManufacturerOrCat($request->input('search'));
}
+54 -27
View File
@@ -52,7 +52,7 @@ class AssetsController extends Controller
* @since [v4.0]
* @return JsonResponse
*/
public function index(Request $request)
public function index(Request $request, $audit = null)
{
$this->authorize('index', Asset::class);
@@ -84,7 +84,7 @@ class AssetsController extends Controller
$filter = array();
if ($request->has('filter')) {
if ($request->filled('filter')) {
$filter = json_decode($request->input('filter'), true);
}
@@ -101,7 +101,7 @@ class AssetsController extends Controller
// These are used by the API to query against specific ID numbers.
// They are also used by the individual searches on detail pages like
// locations, etc.
if ($request->has('status_id')) {
if ($request->filled('status_id')) {
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
@@ -109,45 +109,60 @@ class AssetsController extends Controller
$assets->where('assets.requestable', '=', '1');
}
if ($request->has('model_id')) {
if ($request->filled('model_id')) {
$assets->InModelList([$request->input('model_id')]);
}
if ($request->has('category_id')) {
if ($request->filled('category_id')) {
$assets->InCategory($request->input('category_id'));
}
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$assets->where('assets.location_id', '=', $request->input('location_id'));
}
if ($request->has('supplier_id')) {
if ($request->filled('supplier_id')) {
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
}
if (($request->has('assigned_to')) && ($request->has('assigned_type'))) {
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
->where('assets.assigned_type', '=', $request->input('assigned_type'));
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$assets->where('assets.company_id', '=', $request->input('company_id'));
}
if ($request->has('manufacturer_id')) {
if ($request->filled('manufacturer_id')) {
$assets->ByManufacturer($request->input('manufacturer_id'));
}
if ($request->has('depreciation_id')) {
if ($request->filled('depreciation_id')) {
$assets->ByDepreciationId($request->input('depreciation_id'));
}
$request->has('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
$request->filled('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
$offset = (($assets) && (request('offset') > $assets->count())) ? 0 : request('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
// This is used by the audit reporting routes
if (Gate::allows('audit', Asset::class)) {
switch ($audit) {
case 'due':
$assets->DueOrOverdueForAudit($settings);
break;
case 'overdue':
$assets->overdueForAudit($settings);
break;
}
}
// This is used by the sidenav, mostly
// We switched from using query scopes here because of a Laravel bug
@@ -201,7 +216,7 @@ class AssetsController extends Controller
break;
default:
if ((!$request->has('status_id')) && ($settings->show_archived_in_list!='1')) {
if ((!$request->filled('status_id')) && ($settings->show_archived_in_list!='1')) {
// terrible workaround for complex-query Laravel bug in fulltext
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
@@ -220,7 +235,7 @@ class AssetsController extends Controller
if ((!is_null($filter)) && (count($filter)) > 0) {
$assets->ByFilter($filter);
} elseif ($request->has('search')) {
} elseif ($request->filled('search')) {
$assets->TextSearch($request->input('search'));
}
@@ -326,7 +341,7 @@ class AssetsController extends Controller
*/
public function show($id)
{
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->withCount('checkins', 'checkouts', 'userRequests')->findOrFail($id)) {
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as userRequests_count')->findOrFail($id)) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset);
}
@@ -356,11 +371,11 @@ class AssetsController extends Controller
'assets.status_id'
])->with('model', 'assetstatus', 'assignedTo')->NotArchived(),'company_id', 'assets');
if ($request->has('assetStatusType') && $request->input('assetStatusType') === 'RTD') {
if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') {
$assets = $assets->RTD();
}
if ($request->has('search')) {
if ($request->filled('search')) {
$assets = $assets->AssignedSearch($request->input('search'));
}
@@ -431,9 +446,15 @@ class AssetsController extends Controller
// Update custom fields in the database.
// Validation for these fields is handled through the AssetRequest form request
$model = AssetModel::find($request->get('model_id'));
if ($model->fieldset) {
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
$asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug(), null));
if ($field->field_encrypted=='1') {
if (Gate::allows('admin')) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
@@ -472,18 +493,24 @@ class AssetsController extends Controller
$asset->fill($request->all());
($request->has('model_id')) ?
($request->filled('model_id')) ?
$asset->model()->associate(AssetModel::find($request->get('model_id'))) : null;
($request->has('company_id')) ?
($request->filled('company_id')) ?
$asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : null;
($request->has('rtd_location_id')) ?
($request->filled('rtd_location_id')) ?
$asset->location_id = $request->get('rtd_location_id') : null;
// Update custom fields
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
foreach ($model->fieldset->fields as $field) {
if ($request->has($field->convertUnicodeDbSlug())) {
$asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug()));
if ($field->field_encrypted=='1') {
if (Gate::allows('admin')) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
}
@@ -491,11 +518,11 @@ class AssetsController extends Controller
if ($asset->save()) {
if (($request->has('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;
} elseif (($request->has('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;
} elseif (($request->has('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
$location = $target->id;
}
@@ -650,7 +677,7 @@ class AssetsController extends Controller
$asset->name = Input::get('name');
$asset->location_id = $asset->rtd_location_id;
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$asset->location_id = $request->input('location_id');
}
@@ -24,9 +24,9 @@ class CategoriesController extends Controller
$allowed_columns = ['id', 'name','category_type', 'category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email', 'assets_count', 'accessories_count', 'consumables_count', 'components_count','licenses_count', 'image'];
$categories = Category::select(['id', 'created_at', 'updated_at', 'name','category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email','image'])
->withCount('assets', 'accessories', 'consumables', 'components','licenses');
->withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count','licenses as licenses_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$categories = $categories->TextSearch($request->input('search'));
}
@@ -148,7 +148,7 @@ class CategoriesController extends Controller
'image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$categories = $categories->where('name', 'LIKE', '%'.$request->get('search').'%');
}
@@ -35,9 +35,9 @@ class CompaniesController extends Controller
'components_count',
];
$companies = Company::withCount('assets','licenses','accessories','consumables','components','users');
$companies = Company::withCount('assets as assets_count','licenses as licenses_count','accessories as accessories_count','consumables as consumables_count','components as components_count','users as users_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$companies->TextSearch($request->input('search'));
}
@@ -168,7 +168,7 @@ class CompaniesController extends Controller
'companies.image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->get('search').'%');
}
@@ -27,19 +27,19 @@ class ComponentsController extends Controller
$components = Company::scopeCompanyables(Component::select('components.*')
->with('company', 'location', 'category'));
if ($request->has('search')) {
if ($request->filled('search')) {
$components = $components->TextSearch($request->input('search'));
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$components->where('company_id','=',$request->input('company_id'));
}
if ($request->has('category_id')) {
if ($request->filled('category_id')) {
$components->where('category_id','=',$request->input('category_id'));
}
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$components->where('location_id','=',$request->input('location_id'));
}
@@ -27,19 +27,19 @@ class ConsumablesController extends Controller
->with('company', 'location', 'category', 'users', 'manufacturer')
);
if ($request->has('search')) {
if ($request->filled('search')) {
$consumables = $consumables->TextSearch(e($request->input('search')));
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$consumables->where('company_id','=',$request->input('company_id'));
}
if ($request->has('category_id')) {
if ($request->filled('category_id')) {
$consumables->where('category_id','=',$request->input('category_id'));
}
if ($request->has('manufacturer_id')) {
if ($request->filled('manufacturer_id')) {
$consumables->where('manufacturer_id','=',$request->input('manufacturer_id'));
}
@@ -43,7 +43,7 @@ class CustomFieldsetsController extends Controller
public function index()
{
$this->authorize('index', CustomFieldset::class);
$fieldsets = CustomFieldset::withCount(['fields', 'models'])->get();
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
}
@@ -33,9 +33,9 @@ class DepartmentsController extends Controller
'departments.created_at',
'departments.updated_at',
'departments.image'
])->with('users')->with('location')->with('manager')->with('company')->withCount('users');
])->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$departments = $departments->TextSearch($request->input('search'));
}
@@ -76,7 +76,7 @@ class DepartmentsController extends Controller
$department = new Department;
$department->fill($request->all());
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
if ($department->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.create.success')));
@@ -142,7 +142,7 @@ class DepartmentsController extends Controller
'image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$departments = $departments->where('name', 'LIKE', '%'.$request->get('search').'%');
}
@@ -24,7 +24,7 @@ class DepreciationsController extends Controller
$depreciations = Depreciation::select('id','name','months','user_id','created_at','updated_at');
if ($request->has('search')) {
if ($request->filled('search')) {
$depreciations = $depreciations->TextSearch($request->input('search'));
}
@@ -22,9 +22,9 @@ class GroupsController extends Controller
$this->authorize('view', Group::class);
$allowed_columns = ['id','name','created_at', 'users_count'];
$groups = Group::select('id','name','permissions','created_at','updated_at')->withCount('users');
$groups = Group::select('id','name','permissions','created_at','updated_at')->withCount('users as users_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$groups = $groups->TextSearch($request->input('search'));
}
@@ -25,7 +25,7 @@ class ImportController extends Controller
*/
public function index()
{
//
$this->authorize('import');
$imports = Import::latest()->get();
return (new ImportsTransformer)->transformImports($imports);
@@ -39,10 +39,8 @@ class ImportController extends Controller
*/
public function store()
{
//
if (!Company::isCurrentUserAuthorized()) {
return redirect()->route('hardware.index')->with('error', trans('general.insufficient_permissions'));
} elseif (!config('app.lock_passwords')) {
$this->authorize('import');
if (!config('app.lock_passwords')) {
$files = Input::file('files');
$path = config('app.private_uploads').'/imports';
$results = [];
@@ -119,7 +117,7 @@ class ImportController extends Controller
*/
public function process(ItemImportRequest $request, $import_id)
{
$this->authorize('create', Asset::class);
$this->authorize('import');
// Run a backup immediately before processing
Artisan::call('backup:run');
$errors = $request->import(Import::find($import_id));
@@ -162,7 +160,7 @@ class ImportController extends Controller
*/
public function destroy($import_id)
{
$this->authorize('create', Asset::class);
$this->authorize('import');
$import = Import::find($import_id);
try {
unlink(config('app.private_uploads').'/imports/'.$import->file_path);
+16 -15
View File
@@ -25,59 +25,59 @@ class LicensesController extends Controller
public function index(Request $request)
{
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'freeSeats', 'supplier','category')->withCount('freeSeats'));
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'freeSeats', 'supplier','category')->withCount('freeSeats as free_seats_count'));
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$licenses->where('company_id','=',$request->input('company_id'));
}
if ($request->has('name')) {
if ($request->filled('name')) {
$licenses->where('licenses.name','=',$request->input('name'));
}
if ($request->has('product_key')) {
if ($request->filled('product_key')) {
$licenses->where('licenses.serial','=',$request->input('product_key'));
}
if ($request->has('order_number')) {
if ($request->filled('order_number')) {
$licenses->where('order_number','=',$request->input('order_number'));
}
if ($request->has('purchase_order')) {
if ($request->filled('purchase_order')) {
$licenses->where('purchase_order','=',$request->input('purchase_order'));
}
if ($request->has('license_name')) {
if ($request->filled('license_name')) {
$licenses->where('license_name','=',$request->input('license_name'));
}
if ($request->has('license_email')) {
if ($request->filled('license_email')) {
$licenses->where('license_email','=',$request->input('license_email'));
}
if ($request->has('manufacturer_id')) {
if ($request->filled('manufacturer_id')) {
$licenses->where('manufacturer_id','=',$request->input('manufacturer_id'));
}
if ($request->has('supplier_id')) {
if ($request->filled('supplier_id')) {
$licenses->where('supplier_id','=',$request->input('supplier_id'));
}
if ($request->has('category_id')) {
if ($request->filled('category_id')) {
$licenses->where('category_id','=',$request->input('category_id'));
}
if ($request->has('depreciation_id')) {
if ($request->filled('depreciation_id')) {
$licenses->where('depreciation_id','=',$request->input('depreciation_id'));
}
if ($request->has('supplier_id')) {
if ($request->filled('supplier_id')) {
$licenses->where('supplier_id','=',$request->input('supplier_id'));
}
if ($request->has('search')) {
if ($request->filled('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
@@ -227,7 +227,8 @@ class LicensesController extends Controller
$seats = LicenseSeat::where('license_id', $licenseId)->with('license', 'user', 'asset');
$offset = request('offset', 0);
$offset = (($seats) && (request('offset') > $seats->count())) ? 0 : request('offset', 0);
$limit = request('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -41,11 +41,11 @@ class LocationsController extends Controller
'locations.updated_at',
'locations.image',
'locations.currency'
])->withCount('assignedAssets')
->withCount('assets')
->withCount('users');
])->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('users as users_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$locations = $locations->TextSearch($request->input('search'));
}
@@ -123,9 +123,9 @@ class LocationsController extends Controller
'locations.image',
'locations.currency'
])
->withCount('assignedAssets')
->withCount('assets')
->withCount('users')->findOrFail($id);
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('users as users_count')->findOrFail($id);
return (new LocationsTransformer)->transformLocation($location);
}
@@ -192,7 +192,7 @@ class LocationsController extends Controller
'locations.image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$locations = $locations->where('locations.name', 'LIKE', '%'.$request->get('search').'%');
}
@@ -26,13 +26,13 @@ class ManufacturersController extends Controller
$manufacturers = Manufacturer::select(
array('id','name','url','support_url','support_email','support_phone','created_at','updated_at','image', 'deleted_at')
)->withCount('assets')->withCount('licenses')->withCount('consumables')->withCount('accessories');
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count');
if ($request->input('deleted')=='true') {
$manufacturers->onlyTrashed();
}
if ($request->has('search')) {
if ($request->filled('search')) {
$manufacturers = $manufacturers->TextSearch($request->input('search'));
}
@@ -83,7 +83,7 @@ class ManufacturersController extends Controller
public function show($id)
{
$this->authorize('view', Manufacturer::class);
$manufacturer = Manufacturer::withCount('assets')->withCount('licenses')->withCount('consumables')->withCount('accessories')->findOrFail($id);
$manufacturer = Manufacturer::withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count')->findOrFail($id);
return (new ManufacturersTransformer)->transformManufacturer($manufacturer);
}
@@ -145,7 +145,7 @@ class ManufacturersController extends Controller
'image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$manufacturers = $manufacturers->where('name', 'LIKE', '%'.$request->get('search').'%');
}
+14 -9
View File
@@ -27,15 +27,20 @@ class ProfileController extends Controller
foreach ($checkoutRequests as $checkoutRequest) {
$results['rows'][] = [
'image' => $checkoutRequest->itemRequested()->present()->getImageUrl(),
'name' => $checkoutRequest->itemRequested()->present()->name(),
'type' => $checkoutRequest->itemType(),
'qty' => $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? $checkoutRequest->location()->name : null,
'expected_checkin' => Helper::getFormattedDateObject($checkoutRequest->itemRequested()->expected_checkin, 'datetime'),
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
];
// Make sure the asset and request still exist
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
$results['rows'][] = [
'image' => $checkoutRequest->itemRequested()->present()->getImageUrl(),
'name' => $checkoutRequest->itemRequested()->present()->name(),
'type' => $checkoutRequest->itemType(),
'qty' => $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? $checkoutRequest->location()->name : null,
'expected_checkin' => Helper::getFormattedDateObject($checkoutRequest->itemRequested()->expected_checkin, 'datetime'),
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
];
}
}
return $results;
}
@@ -22,25 +22,25 @@ class ReportsController extends Controller
$actionlogs = Actionlog::with('item', 'user', 'target','location');
if ($request->has('search')) {
if ($request->filled('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
}
if (($request->has('target_type')) && ($request->has('target_id'))) {
if (($request->filled('target_type')) && ($request->filled('target_id'))) {
$actionlogs = $actionlogs->where('target_id','=',$request->input('target_id'))
->where('target_type','=',"App\\Models\\".ucwords($request->input('target_type')));
}
if (($request->has('item_type')) && ($request->has('item_id'))) {
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
$actionlogs = $actionlogs->where('item_id','=',$request->input('item_id'))
->where('item_type','=',"App\\Models\\".ucwords($request->input('item_type')));
}
if ($request->has('action_type')) {
if ($request->filled('action_type')) {
$actionlogs = $actionlogs->where('action_type','=',$request->input('action_type'))->orderBy('created_at', 'desc');
}
if ($request->has('uploads')) {
if ($request->filled('uploads')) {
$actionlogs = $actionlogs->whereNotNull('filename')->orderBy('created_at', 'desc');
}
@@ -24,9 +24,9 @@ class StatuslabelsController extends Controller
$this->authorize('view', Statuslabel::class);
$allowed_columns = ['id','name','created_at', 'assets_count','color','default_label'];
$statuslabels = Statuslabel::withCount('assets');
$statuslabels = Statuslabel::withCount('assets as assets_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$statuslabels = $statuslabels->TextSearch($request->input('search'));
}
@@ -55,7 +55,7 @@ class StatuslabelsController extends Controller
$this->authorize('create', Statuslabel::class);
$request->except('deployable', 'pending','archived');
if (!$request->has('type')) {
if (!$request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, ["type" => ["Status label type is required."]]),500);
}
@@ -106,7 +106,7 @@ class StatuslabelsController extends Controller
$request->except('deployable', 'pending','archived');
if (!$request->has('type')) {
if (!$request->filled('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
}
@@ -162,7 +162,7 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::with('assets')->groupBy('id')->withCount('assets')->get();
$statuslabels = Statuslabel::with('assets')->groupBy('id')->withCount('assets as assets_count')->get();
$labels=[];
$points=[];
@@ -26,10 +26,10 @@ class SuppliersController extends Controller
$suppliers = Supplier::select(
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image','notes')
)->withCount('assets')->withCount('licenses')->withCount('accessories');
)->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('accessories as accessories_count');
if ($request->has('search')) {
if ($request->filled('search')) {
$suppliers = $suppliers->TextSearch($request->input('search'));
}
@@ -115,7 +115,7 @@ class SuppliersController extends Controller
public function destroy($id)
{
$this->authorize('delete', Supplier::class);
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances','assets', 'licenses')->findOrFail($id);
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count','assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
$this->authorize('delete', $supplier);
@@ -153,7 +153,7 @@ class SuppliersController extends Controller
'image',
]);
if ($request->has('search')) {
if ($request->filled('search')) {
$suppliers = $suppliers->where('suppliers.name', 'LIKE', '%'.$request->get('search').'%');
}
+41 -13
View File
@@ -12,6 +12,7 @@ use App\Http\Requests\SaveUserRequest;
use App\Models\Asset;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Http\Transformers\AccessoriesTransformer;
class UsersController extends Controller
{
@@ -51,36 +52,37 @@ class UsersController extends Controller
'users.phone',
'users.state',
'users.two_factor_enrolled',
'users.two_factor_optin',
'users.updated_at',
'users.username',
'users.zip',
])->with('manager', 'groups', 'userloc', 'company', 'department','assets','licenses','accessories','consumables')
->withCount('assets','licenses','accessories','consumables');
->withCount('assets as assets_count','licenses as licenses_count','accessories as accessories_count','consumables as consumables_count');
$users = Company::scopeCompanyables($users);
if (($request->has('deleted')) && ($request->input('deleted')=='true')) {
if (($request->filled('deleted')) && ($request->input('deleted')=='true')) {
$users = $users->GetDeleted();
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$users = $users->where('users.company_id', '=', $request->input('company_id'));
}
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$users = $users->where('users.location_id', '=', $request->input('location_id'));
}
if ($request->has('group_id')) {
if ($request->filled('group_id')) {
$users = $users->ByGroup($request->get('group_id'));
}
if ($request->has('department_id')) {
if ($request->filled('department_id')) {
$users = $users->where('users.department_id','=',$request->input('department_id'));
}
if ($request->has('search')) {
if ($request->filled('search')) {
$users = $users->TextSearch($request->input('search'));
}
@@ -98,6 +100,9 @@ class UsersController extends Controller
case 'department':
$users = $users->OrderDepartment($order);
break;
case 'company':
$users = $users->OrderCompany($order);
break;
default:
$allowed_columns =
[
@@ -146,9 +151,8 @@ class UsersController extends Controller
$users = Company::scopeCompanyables($users);
if ($request->has('search')) {
$users = $users->where('first_name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('last_name', 'LIKE', '%'.$request->get('search').'%')
if ($request->filled('search')) {
$users = $users->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
}
@@ -200,7 +204,7 @@ class UsersController extends Controller
$user->password = bcrypt($request->get('password', $tmp_pass));
if ($user->save()) {
if ($request->has('groups')) {
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync(array());
@@ -246,7 +250,7 @@ class UsersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
}
if ($request->has('password')) {
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
@@ -255,6 +259,13 @@ class UsersController extends Controller
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
if ($user->save()) {
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync(array());
}
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
}
@@ -302,6 +313,23 @@ class UsersController extends Controller
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
/**
* Return JSON containing a list of accessories assigned to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.6.14]
* @param $userId
* @return string JSON
*/
public function accessories($id)
{
$this->authorize('view', User::class);
$user = User::findOrFail($id);
$this->authorize('view', Accessory::class);
$accessories = $user->accessories;
return (new AccessoriesTransformer)->transformAccessories($accessories, $accessories->count());
}
/**
* Reset the user's two-factor status
*
@@ -315,7 +343,7 @@ class UsersController extends Controller
$this->authorize('update', User::class);
if ($request->has('id')) {
if ($request->filled('id')) {
try {
$user = User::find($request->get('id'));
$user->two_factor_secret = null;
@@ -65,15 +65,15 @@ class AssetCheckinController extends Controller
$asset->assignedTo()->disassociate($asset);
$asset->assigned_type = null;
$asset->accepted = null;
$asset->name = e($request->get('name'));
$asset->name = $request->get('name');
if ($request->has('status_id')) {
if ($request->filled('status_id')) {
$asset->status_id = e($request->get('status_id'));
}
$asset->location_id = $asset->rtd_location_id;
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$asset->location_id = e($request->get('location_id'));
}
@@ -93,7 +93,7 @@ class AssetCheckinController extends Controller
$data['model_name'] = $asset->model->name;
$data['model_number'] = $asset->model->model_number;
if ($backto=='user') {
if (($user) && ($backto =='user')) {
return redirect()->route("users.show", $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
}
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
@@ -71,12 +71,12 @@ class AssetCheckoutController extends Controller
$asset = $this->updateAssetLocation($asset, $target);
$checkout_at = date("Y-m-d H:i:s");
if (($request->has('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
$checkout_at = $request->get('checkout_at');
}
$expected_checkin = '';
if ($request->has('expected_checkin')) {
if ($request->filled('expected_checkin')) {
$expected_checkin = $request->get('expected_checkin');
}
@@ -111,12 +111,16 @@ class AssetFilesController extends Controller
$this->authorize('update', $asset);
$log = Actionlog::find($fileId);
$full_filename = $destinationPath.'/'.$log->filename;
if (file_exists($full_filename)) {
unlink($destinationPath.'/'.$log->filename);
if ($log) {
$full_filename = $destinationPath.'/'.$log->filename;
if (file_exists($full_filename)) {
unlink($destinationPath.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
return redirect()->back()->with('error', 'Could not find matching upload log.');
}
// Redirect to the hardware management page
@@ -97,7 +97,7 @@ class AssetModelsController extends Controller
$path = app('models_upload_path');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
@@ -194,7 +194,7 @@ class AssetModelsController extends Controller
$file_name = $model->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('models_upload_path').$file_name);
@@ -209,7 +209,7 @@ class AssetModelsController extends Controller
try {
unlink(app('models_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -246,7 +246,7 @@ class AssetModelsController extends Controller
try {
unlink(public_path().'/uploads/models/'.$model->image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -373,7 +373,7 @@ class AssetModelsController extends Controller
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets')->orderBy('assets_count', 'ASC')->get();
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->orderBy('assets_count', 'ASC')->get();
// If deleting....
if ($request->input('bulk_actions')=='delete') {
@@ -420,10 +420,10 @@ class AssetModelsController extends Controller
$update_array = array();
if (($request->has('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) {
if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) {
$update_array['manufacturer_id'] = $request->input('manufacturer_id');
}
if (($request->has('category_id') && ($request->input('category_id')!='NC'))) {
if (($request->filled('category_id') && ($request->input('category_id')!='NC'))) {
$update_array['category_id'] = $request->input('category_id');
}
if ($request->input('fieldset_id')!='NC') {
@@ -461,7 +461,7 @@ class AssetModelsController extends Controller
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets')->get();
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets as assets_count')->get();
$del_error_count = 0;
$del_count = 0;
+25 -13
View File
@@ -71,7 +71,7 @@ class AssetsController extends Controller
public function index(Request $request)
{
$this->authorize('index', Asset::class);
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$company = Company::find($request->input('company_id'));
} else {
$company = null;
@@ -96,7 +96,7 @@ class AssetsController extends Controller
->with('item', new Asset)
->with('statuslabel_types', Helper::statusTypeList());
if ($request->has('model_id')) {
if ($request->filled('model_id')) {
$selected_model = AssetModel::find($request->input('model_id'));
$view->with('selected_model', $selected_model);
}
@@ -143,7 +143,7 @@ class AssetsController extends Controller
}
// Create the image (if one was chosen.)
if ($request->has('image')) {
if ($request->filled('image')) {
$image = $request->input('image');
// After modification, the image is prefixed by mime info like the following:
@@ -163,7 +163,7 @@ class AssetsController extends Controller
}
$path = public_path('uploads/assets/'.$file_name);
try {
Image::make($image)->resize(500, 500, function ($constraint) {
Image::make($image)->resize(800, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -183,7 +183,7 @@ class AssetsController extends Controller
// Validation for these fields is handled through the AssetRequest form request
$model = AssetModel::find($request->get('model_id'));
if ($model->fieldset) {
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted=='1') {
if (Gate::allows('admin')) {
@@ -313,7 +313,7 @@ class AssetsController extends Controller
$asset->supplier_id = $request->input('supplier_id', null);
// If the box isn't checked, it's not in the request at all.
$asset->requestable = $request->has('requestable');
$asset->requestable = $request->filled('requestable');
$asset->rtd_location_id = $request->input('rtd_location_id', null);
if ($asset->assigned_to=='') {
@@ -321,12 +321,12 @@ class AssetsController extends Controller
}
if ($request->has('image_delete')) {
if ($request->filled('image_delete')) {
try {
unlink(public_path().'/uploads/assets/'.$asset->image);
$asset->image = '';
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -343,7 +343,7 @@ class AssetsController extends Controller
$asset->physical = '1';
// Update the image
if ($request->has('image')) {
if ($request->filled('image')) {
$image = $request->input('image');
// See postCreate for more explaination of the following.
$header = explode(';', $image, 2)[0];
@@ -359,7 +359,7 @@ class AssetsController extends Controller
$file_name = str_random(25).".".$extension;
$path = public_path('uploads/assets/'.$file_name);
try {
Image::make($image)->resize(500, 500, function ($constraint) {
Image::make($image)->resize(800, 800, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -380,7 +380,7 @@ class AssetsController extends Controller
// FIXME: No idea why this is returning a Builder error on db_column_name.
// Need to investigate and fix. Using static method for now.
$model = AssetModel::find($request->get('model_id'));
if ($model->fieldset) {
if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted=='1') {
if (Gate::allows('admin')) {
@@ -579,7 +579,7 @@ class AssetsController extends Controller
//get the first row, usually the CSV header
//$headers = $csv->fetchOne();
$results = $csv->fetchAssoc();
$results = $csv->getRecords();
$item = array();
$status = array();
$status['error'] = array();
@@ -744,6 +744,18 @@ class AssetsController extends Controller
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
public function dueForAudit()
{
$this->authorize('audit', Asset::class);
return view('hardware/audit-due');
}
public function overdueForAudit()
{
$this->authorize('audit', Asset::class);
return view('hardware/audit-overdue');
}
public function auditStore(AssetFileRequest $request, $id)
{
@@ -781,7 +793,7 @@ class AssetsController extends Controller
$filename = 'audit-'.$asset->id.'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
$file->move($destinationPath, $filename);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
+54 -31
View File
@@ -193,7 +193,6 @@ class LoginController extends Controller
if ($user = Auth::user()) {
$user->last_login = \Carbon::now();
\Log::debug('Last login:'.$user->last_login);
$user->save();
}
// Redirect to the users page
@@ -209,26 +208,33 @@ class LoginController extends Controller
public function getTwoFactorEnroll()
{
// Make sure the user is logged in
if (!Auth::check()) {
return redirect()->route('login')->with('error', 'You must be logged in.');
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
$settings = Setting::getSettings();
$user = Auth::user();
$google2fa = app()->make('PragmaRX\Google2FA\Contracts\Google2FA');
if ($user->two_factor_secret=='') {
$user->two_factor_secret = $google2fa->generateSecretKey(32);
$user->save();
// We wouldn't normally see this page if 2FA isn't enforced via the
// \App\Http\Middleware\CheckForTwoFactor middleware AND if a device isn't enrolled,
// but let's check check anyway in case there's a browser history or back button thing.
// While you can access this page directly, enrolling a device when 2FA isn't enforced
// won't cause any harm.
if (($user->two_factor_secret!='') && ($user->two_factor_enrolled==1)) {
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.already_enrolled'));
}
$google2fa = new Google2FA();
$secret = $google2fa->generateSecretKey();
$user->two_factor_secret = $secret;
$user->save();
$google2fa_url = $google2fa->getQRCodeGoogleUrl(
urlencode(Setting::getSettings()->site_name),
urlencode($user->username),
$user->two_factor_secret
);
return view('auth.two_factor_enroll')->with('google2fa_url', $google2fa_url);
$barcode = new \Com\Tecnick\Barcode\Barcode();
$barcode_obj = $barcode->getBarcodeObj('QRCODE', 'otpauth://totp/'.urlencode($settings->site_name).':'.urlencode($user->username).'?secret='.urlencode($secret).'&issuer=Snipe-IT&period=30', 300, 300, 'black', array(-2, -2, -2, -2));
return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj);
}
@@ -240,6 +246,20 @@ class LoginController extends Controller
*/
public function getTwoFactorAuth()
{
// Check that the user is logged in
if (!Auth::check()) {
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
$user = Auth::user();
// Check whether there is a device enrolled.
// This *should* be handled via the \App\Http\Middleware\CheckForTwoFactor middleware
// but we're just making sure (in case someone edited the database directly, etc)
if (($user->two_factor_secret=='') || ($user->two_factor_enrolled!=1)) {
return redirect()->route('two-factor-enroll');
}
return view('auth.two_factor');
}
@@ -252,22 +272,25 @@ class LoginController extends Controller
{
if (!Auth::check()) {
return redirect()->route('login')->with('error', 'You must be logged in.');
return redirect()->route('login')->with('error', trans('auth/general.login_prompt'));
}
if (!$request->filled('two_factor_secret')) {
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
}
$user = Auth::user();
$secret = $request->get('two_factor_secret');
$google2fa = app()->make('PragmaRX\Google2FA\Contracts\Google2FA');
$valid = $google2fa->verifyKey($user->two_factor_secret, $secret);
$google2fa = new Google2FA();
$secret = $request->input('two_factor_secret');
if ($valid) {
if ($google2fa->verifyKey($user->two_factor_secret, $secret)) {
$user->two_factor_enrolled = 1;
$user->save();
$request->session()->put('2fa_authed', 'true');
return redirect()->route('home')->with('success', 'You are logged in!');
}
return redirect()->route('two-factor')->with('error', 'Invalid two-factor code');
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code'));
}
@@ -290,7 +313,7 @@ class LoginController extends Controller
return redirect()->away($customLogoutUrl);
}
return redirect()->route('login')->with('success', 'You have successfully logged out!');
return redirect()->route('login')->with('success', trans('auth/message.logout.success'));
}
@@ -315,11 +338,11 @@ class LoginController extends Controller
}
/**
* Redirect the user after determining they are locked out.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
* Redirect the user after determining they are locked out.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendLockoutResponse(Request $request)
{
$seconds = $this->limiter()->availableIn(
@@ -330,18 +353,18 @@ class LoginController extends Controller
$message = \Lang::get('auth/message.throttle', ['minutes' => $minutes]);
return redirect()->back()
return redirect()->back()
->withInput($request->only($this->username(), 'remember'))
->withErrors([$this->username() => $message]);
}
/**
* Override the lockout time and duration
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
* Override the lockout time and duration
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function hasTooManyLoginAttempts(Request $request)
{
$lockoutTime = config('auth.throttle.lockout_duration');
+20 -20
View File
@@ -26,13 +26,13 @@ class BulkAssetsController extends Controller
{
$this->authorize('update', Asset::class);
if (!$request->has('ids')) {
if (!$request->filled('ids')) {
return redirect()->back()->with('error', 'No assets selected');
}
$asset_ids = array_keys($request->input('ids'));
if ($request->has('bulk_actions')) {
if ($request->filled('bulk_actions')) {
switch($request->input('bulk_actions')) {
case 'labels':
return view('hardware/labels')
@@ -68,22 +68,22 @@ class BulkAssetsController extends Controller
\Log::debug($request->input('ids'));
if(!$request->has('ids') || count($request->input('ids')) <= 0) {
if(!$request->filled('ids') || count($request->input('ids')) <= 0) {
return redirect()->route("hardware.index")->with('warning', trans('No assets selected, so nothing was updated.'));
}
$assets = array_keys($request->input('ids'));
if (($request->has('purchase_date'))
|| ($request->has('purchase_cost'))
|| ($request->has('supplier_id'))
|| ($request->has('order_number'))
|| ($request->has('warranty_months'))
|| ($request->has('rtd_location_id'))
|| ($request->has('requestable'))
|| ($request->has('company_id'))
|| ($request->has('status_id'))
|| ($request->has('model_id'))
if (($request->filled('purchase_date'))
|| ($request->filled('purchase_cost'))
|| ($request->filled('supplier_id'))
|| ($request->filled('order_number'))
|| ($request->filled('warranty_months'))
|| ($request->filled('rtd_location_id'))
|| ($request->filled('requestable'))
|| ($request->filled('company_id'))
|| ($request->filled('status_id'))
|| ($request->filled('model_id'))
) {
foreach ($assets as $assetId) {
$this->update_array = [];
@@ -96,20 +96,20 @@ class BulkAssetsController extends Controller
->conditionallyAddItem('supplier_id')
->conditionallyAddItem('warranty_months');
if ($request->has('purchase_cost')) {
if ($request->filled('purchase_cost')) {
$this->update_array['purchase_cost'] = Helper::ParseFloat($request->input('purchase_cost'));
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$this->update_array['company_id'] = $request->input('company_id');
if ($request->input('company_id')=="clear") {
$this->update_array['company_id'] = null;
}
}
if ($request->has('rtd_location_id')) {
if ($request->filled('rtd_location_id')) {
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
if (($request->has('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
$this->update_array['location_id'] = $request->input('rtd_location_id');
}
}
@@ -155,7 +155,7 @@ class BulkAssetsController extends Controller
{
$this->authorize('delete', Asset::class);
if ($request->has('ids')) {
if ($request->filled('ids')) {
$assets = Asset::find($request->get('ids'));
foreach ($assets as $asset) {
$update_array['deleted_at'] = date('Y-m-d H:i:s');
@@ -206,13 +206,13 @@ class BulkAssetsController extends Controller
}
}
$checkout_at = date("Y-m-d H:i:s");
if (($request->has('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) {
$checkout_at = e($request->get('checkout_at'));
}
$expected_checkin = '';
if ($request->has('expected_checkin')) {
if ($request->filled('expected_checkin')) {
$expected_checkin = e($request->get('expected_checkin'));
}
@@ -87,7 +87,7 @@ class CategoriesController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/categories/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -164,7 +164,7 @@ class CategoriesController extends Controller
$file_name = $category->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('categories_upload_path').$file_name);
@@ -179,7 +179,7 @@ class CategoriesController extends Controller
try {
unlink(app('categories_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
+3 -3
View File
@@ -67,7 +67,7 @@ final class CompaniesController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/companies/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -133,7 +133,7 @@ final class CompaniesController extends Controller
$file_name = $company->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('companies_upload_path').$file_name);
@@ -148,7 +148,7 @@ final class CompaniesController extends Controller
try {
unlink(app('companies_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -95,7 +95,7 @@ class ComponentsController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -168,7 +168,7 @@ class ComponentsController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -91,7 +91,7 @@ class ConsumablesController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/consumables/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -162,7 +162,7 @@ class ConsumablesController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/consumables/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -44,7 +44,7 @@ class CustomFieldsetsController extends Controller
$custom_fields_list = ["" => "Add New Field to Fieldset"] + CustomField::pluck("name", "id")->toArray();
$maxid = 0;
foreach ($cfset->fields() as $field) {
foreach ($cfset->fields as $field) {
if ($field->pivot->order > $maxid) {
$maxid=$field->pivot->order;
}
@@ -172,7 +172,7 @@ class CustomFieldsetsController extends Controller
* @since [v1.8]
* @return View
*/
public function associate($id)
public function associate(Request $request, $id)
{
$set = CustomFieldset::find($id);
@@ -180,12 +180,12 @@ class CustomFieldsetsController extends Controller
$this->authorize('update', $set);
foreach ($set->fields as $field) {
if ($field->id == Input::get('field_id')) {
if ($field->id == $request->input('field_id')) {
return redirect()->route("fieldsets.show", [$id])->withInput()->withErrors(['field_id' => trans('admin/custom_fields/message.field.already_added')]);
}
}
$results=$set->fields()->attach(Input::get('field_id'), ["required" => (Input::get('required') == "on"),"order" => Input::get('order')]);
$results = $set->fields()->attach(Input::get('field_id'), ["required" => ($request->input('required') == "on"),"order" => $request->input('order', 1)]);
return redirect()->route("fieldsets.show", [$id])->with("success", trans('admin/custom_fields/message.field.create.assoc_success'));
}
@@ -30,7 +30,7 @@ class DepartmentsController extends Controller
{
$this->authorize('index', Department::class);
$company = null;
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$company = Company::find($request->input('company_id'));
}
return view('departments/index')->with('company', $company);
@@ -51,13 +51,13 @@ class DepartmentsController extends Controller
$department = new Department;
$department->fill($request->all());
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/departments/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -162,7 +162,7 @@ class DepartmentsController extends Controller
$this->authorize('update', $department);
$department->fill($request->all());
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
$department->manager_id = ($request->filled('manager_id' ) ? $request->input('manager_id') : null);
$old_image = $department->image;
@@ -176,7 +176,7 @@ class DepartmentsController extends Controller
$file_name = $department->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('departments_upload_path').$file_name);
@@ -191,7 +191,7 @@ class DepartmentsController extends Controller
try {
unlink(app('departments_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ class ImportsController extends Controller
{
public function index()
{
$this->authorize('create', Asset::class);
$this->authorize('import');
$imports = Import::latest()->get();
$imports = (new ImportsTransformer)->transformImports($imports);
return view('importer/import')->with('imports', $imports);
+37 -43
View File
@@ -179,7 +179,9 @@ class LicensesController extends Controller
$license->purchase_date = $request->input('purchase_date');
$license->purchase_order = $request->input('purchase_order');
$license->reassignable = $request->input('reassignable', 0);
$license->serial = $request->input('serial');
if (Gate::allows('viewKeys', $license)) {
$license->serial = $request->input('serial');
}
$license->termination_date = $request->input('termination_date');
$license->seats = e($request->input('seats'));
$license->manufacturer_id = $request->input('manufacturer_id');
@@ -413,20 +415,7 @@ class LicensesController extends Controller
return redirect()->back()->withInput();
}
// Declare the rules for the form validation
$rules = array(
'note' => 'string',
'notes' => 'string',
);
// Create a new validator instance from our validation rules
$validator = Validator::make(Input::all(), $rules);
// If validation fails, we'll exit the operation now.
if ($validator->fails()) {
// Ooops.. something went wrong
return redirect()->back()->withInput()->withErrors($validator);
}
$return_to = User::find($licenseSeat->assigned_to);
if (!$return_to) {
$return_to = Asset::find($licenseSeat->asset_id);
@@ -438,7 +427,7 @@ class LicensesController extends Controller
// Was the asset updated?
if ($licenseSeat->save()) {
$licenseSeat->logCheckin($return_to, e(request('note')));
$licenseSeat->logCheckin($license, e(request('note')));
if ($backTo=='user') {
return redirect()->route("users.show", $return_to->id)->with('success', trans('admin/licenses/message.checkin.success'));
}
@@ -556,21 +545,24 @@ class LicensesController extends Controller
$destinationPath = config('app.private_uploads').'/licenses';
// the license is valid
if (isset($license->id)) {
if ($license) {
$this->authorize('edit', $license);
$log = Actionlog::find($fileId);
$full_filename = $destinationPath.'/'.$log->filename;
if (file_exists($full_filename)) {
unlink($destinationPath.'/'.$log->filename);
if ($log) {
$full_filename = $destinationPath.'/'.$log->filename;
if (file_exists($full_filename)) {
unlink($destinationPath.'/'.$log->filename);
}
$log->delete();
return redirect()->back()->with('success', trans('admin/licenses/message.deletefile.success'));
}
$log->delete();
return redirect()->back()->with('success', trans('admin/licenses/message.deletefile.success'));
return redirect()->back()->with('error', 'Could not locate that file.');
}
// Prepare the error message
$error = trans('admin/licenses/message.does_not_exist', compact('id'));
// Redirect to the licence management page
return redirect()->route('licenses.index')->with('error', $error);
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', compact('id')));
}
@@ -593,29 +585,31 @@ class LicensesController extends Controller
if (isset($license->id)) {
$this->authorize('view', $license);
$log = Actionlog::find($fileId);
$file = $log->get_src('licenses');
if ($log) {
if ($file =='') {
return response('File not found on server', 404)
->header('Content-Type', 'text/plain');
}
$mimetype = \File::mimeType($file);
if (!file_exists($file)) {
return response('File '.$file.' not found on server', 404)
->header('Content-Type', 'text/plain');
}
if ($download != 'true') {
if ($contents = file_get_contents($file)) {
return Response::make($contents)->header('Content-Type', $mimetype);
$file = $log->get_src('licenses');
if ($file =='') {
return response('File not found on server', 404)
->header('Content-Type', 'text/plain');
}
return JsonResponse::create(["error" => "Failed validation: "], 500);
$mimetype = \File::mimeType($file);
if (!file_exists($file)) {
return response('File '.$file.' not found on server', 404)
->header('Content-Type', 'text/plain');
}
if ($download != 'true') {
if ($contents = file_get_contents($file)) {
return Response::make($contents)->header('Content-Type', $mimetype);
}
return JsonResponse::create(["error" => "Failed validation: "], 500);
}
return Response::download($file);
}
return Response::download($file);
}
+3 -3
View File
@@ -101,7 +101,7 @@ class LocationsController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/locations/'.$file_name);
Image::make($image->getRealPath())->resize(600, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -185,7 +185,7 @@ class LocationsController extends Controller
$file_name = $location->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(600, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('locations_upload_path').$file_name);
@@ -200,7 +200,7 @@ class LocationsController extends Controller
try {
unlink(app('locations_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -81,7 +81,7 @@ class ManufacturersController extends Controller
$image = $request->file('image');
$file_name = str_slug($image->getClientOriginalName()).".".$image->getClientOriginalExtension();
$path = public_path('uploads/manufacturers/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -155,7 +155,7 @@ class ManufacturersController extends Controller
$file_name = $manufacturer->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('manufacturers_upload_path').$file_name);
@@ -170,7 +170,7 @@ class ManufacturersController extends Controller
try {
unlink(app('manufacturers_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -207,7 +207,7 @@ class ManufacturersController extends Controller
try {
unlink(public_path().'/uploads/manufacturers/'.$manufacturer->image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -49,6 +49,9 @@ class ProfileController extends Controller
$user->last_name = $request->input('last_name');
$user->website = $request->input('website');
$user->gravatar = $request->input('gravatar');
$user->phone = $request->input('phone');
if (!config('app.lock_passwords')) {
$user->locale = $request->input('locale', 'en');
+76 -76
View File
@@ -314,65 +314,65 @@ class ReportsController extends Controller
// Open output stream
$handle = fopen('php://output', 'w');
if ($request->has('use_bom')) {
if ($request->filled('use_bom')) {
fprintf($handle, chr(0xEF) . chr(0xBB) . chr(0xBF));
}
$header = [];
if ($request->has('company')) {
if ($request->filled('company')) {
$header[] = trans('general.company');
}
if ($request->has('asset_name')) {
if ($request->filled('asset_name')) {
$header[] = trans('admin/hardware/form.name');
}
if ($request->has('asset_tag')) {
if ($request->filled('asset_tag')) {
$header[] = trans('admin/hardware/table.asset_tag');
}
if ($request->has('model')) {
if ($request->filled('model')) {
$header[] = trans('admin/hardware/form.model');
$header[] = trans('general.model_no');
}
if ($request->has('category')) {
if ($request->filled('category')) {
$header[] = trans('general.category');
}
if ($request->has('manufacturer')) {
if ($request->filled('manufacturer')) {
$header[] = trans('admin/hardware/form.manufacturer');
}
if ($request->has('serial')) {
if ($request->filled('serial')) {
$header[] = trans('admin/hardware/table.serial');
}
if ($request->has('purchase_date')) {
if ($request->filled('purchase_date')) {
$header[] = trans('admin/hardware/table.purchase_date');
}
if (($request->has('purchase_cost')) || ($request->has('depreciation'))) {
if (($request->filled('purchase_cost')) || ($request->filled('depreciation'))) {
$header[] = trans('admin/hardware/table.purchase_cost');
}
if ($request->has('eol')) {
if ($request->filled('eol')) {
$header[] = trans('admin/hardware/table.eol');
}
if ($request->has('order')) {
if ($request->filled('order')) {
$header[] = trans('admin/hardware/form.order');
}
if ($request->has('supplier')) {
if ($request->filled('supplier')) {
$header[] = trans('general.supplier');
}
if ($request->has('location')) {
if ($request->filled('location')) {
$header[] = trans('admin/hardware/table.location');
}
if ($request->has('location_address')) {
if ($request->filled('location_address')) {
$header[] = trans('general.address');
$header[] = trans('general.address');
$header[] = trans('general.city');
@@ -381,11 +381,11 @@ class ReportsController extends Controller
$header[] = trans('general.zip');
}
if ($request->has('rtd_location')) {
if ($request->filled('rtd_location')) {
$header[] = trans('admin/hardware/form.default_location');
}
if ($request->has('rtd_location_address')) {
if ($request->filled('rtd_location_address')) {
$header[] = trans('general.address');
$header[] = trans('general.address');
$header[] = trans('general.city');
@@ -395,65 +395,65 @@ class ReportsController extends Controller
}
if ($request->has('assigned_to')) {
if ($request->filled('assigned_to')) {
$header[] = trans('admin/hardware/table.checkoutto');
$header[] = trans('general.type');
}
if ($request->has('username')) {
if ($request->filled('username')) {
$header[] = 'Username';
}
if ($request->has('employee_num')) {
if ($request->filled('employee_num')) {
$header[] = 'Employee No.';
}
if ($request->has('manager')) {
if ($request->filled('manager')) {
$header[] = trans('admin/users/table.manager');
}
if ($request->has('department')) {
if ($request->filled('department')) {
$header[] = trans('general.department');
}
if ($request->has('status')) {
if ($request->filled('status')) {
$header[] = trans('general.status');
}
if ($request->has('warranty')) {
if ($request->filled('warranty')) {
$header[] = 'Warranty';
$header[] = 'Warranty Expires';
}
if ($request->has('depreciation')) {
if ($request->filled('depreciation')) {
$header[] = 'Value';
$header[] = 'Diff';
}
if ($request->has('checkout_date')) {
if ($request->filled('checkout_date')) {
$header[] = trans('admin/hardware/table.checkout_date');
}
if ($request->has('expected_checkin')) {
if ($request->filled('expected_checkin')) {
$header[] = trans('admin/hardware/form.expected_checkin');
}
if ($request->has('created_at')) {
if ($request->filled('created_at')) {
$header[] = trans('general.created_at');
}
if ($request->has('updated_at')) {
if ($request->filled('updated_at')) {
$header[] = trans('general.updated_at');
}
if ($request->has('last_audit_date')) {
if ($request->filled('last_audit_date')) {
$header[] = trans('general.last_audit');
}
if ($request->has('next_audit_date')) {
if ($request->filled('next_audit_date')) {
$header[] = trans('general.next_audit_date');
}
if ($request->has('notes')) {
if ($request->filled('notes')) {
$header[] = trans('general.notes');
}
@@ -471,52 +471,52 @@ class ReportsController extends Controller
'location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer','supplier');
if ($request->has('by_location_id')) {
if ($request->filled('by_location_id')) {
$assets->where('assets.location_id', $request->input('by_location_id'));
}
if ($request->has('by_rtd_location_id')) {
if ($request->filled('by_rtd_location_id')) {
\Log::debug('RTD location should match: '.$request->input('by_rtd_location_id'));
$assets->where('assets.rtd_location_id', $request->input('by_rtd_location_id'));
}
if ($request->has('by_supplier_id')) {
if ($request->filled('by_supplier_id')) {
$assets->where('assets.supplier_id', $request->input('by_supplier_id'));
}
if ($request->has('by_company_id')) {
if ($request->filled('by_company_id')) {
$assets->where('assets.company_id', $request->input('by_company_id'));
}
if ($request->has('by_model_id')) {
if ($request->filled('by_model_id')) {
$assets->where('assets.model_id', $request->input('by_model_id'));
}
if ($request->has('by_category_id')) {
if ($request->filled('by_category_id')) {
$assets->InCategory($request->input('by_category_id'));
}
if ($request->has('by_manufacturer_id')) {
if ($request->filled('by_manufacturer_id')) {
$assets->ByManufacturer($request->input('by_manufacturer_id'));
}
if ($request->has('by_order_number')) {
if ($request->filled('by_order_number')) {
$assets->where('assets.order_number', $request->input('by_order_number'));
}
if ($request->has('by_status_id')) {
if ($request->filled('by_status_id')) {
$assets->where('assets.status_id', $request->input('by_status_id'));
}
if (($request->has('purchase_start')) && ($request->has('purchase_end'))) {
if (($request->filled('purchase_start')) && ($request->filled('purchase_end'))) {
$assets->whereBetween('assets.purchase_date', [$request->input('purchase_start'), $request->input('purchase_end')]);
}
if (($request->has('created_start')) && ($request->has('created_end'))) {
if (($request->filled('created_start')) && ($request->filled('created_end'))) {
$assets->whereBetween('assets.created_at', [$request->input('created_start'), $request->input('created_end')]);
}
if (($request->has('expected_checkin_start')) && ($request->has('expected_checkin_end'))) {
if (($request->filled('expected_checkin_start')) && ($request->filled('expected_checkin_end'))) {
$assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]);
}
@@ -525,61 +525,61 @@ class ReportsController extends Controller
foreach ($assets as $asset) {
$row = [];
if ($request->has('company')) {
if ($request->filled('company')) {
$row[] = ($asset->company) ? $asset->company->name : '';
}
if ($request->has('asset_name')) {
if ($request->filled('asset_name')) {
$row[] = ($asset->name) ? $asset->name : '';
}
if ($request->has('asset_tag')) {
if ($request->filled('asset_tag')) {
$row[] = ($asset->asset_tag) ? $asset->asset_tag : '';
}
if ($request->has('model')) {
if ($request->filled('model')) {
$row[] = ($asset->model) ? $asset->model->name : '';
$row[] = ($asset->model) ? $asset->model->model_number : '';
}
if ($request->has('category')) {
if ($request->filled('category')) {
$row[] = (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '';
}
if ($request->has('manufacturer')) {
if ($request->filled('manufacturer')) {
$row[] = ($asset->model && $asset->model->manufacturer) ? $asset->model->manufacturer->name : '';
}
if ($request->has('serial')) {
if ($request->filled('serial')) {
$row[] = ($asset->serial) ? $asset->serial : '';
}
if ($request->has('purchase_date')) {
if ($request->filled('purchase_date')) {
$row[] = ($asset->purchase_date) ? $asset->purchase_date : '';
}
if ($request->has('purchase_cost')) {
if ($request->filled('purchase_cost')) {
$row[] = ($asset->purchase_cost) ? Helper::formatCurrencyOutput($asset->purchase_cost) : '';
}
if ($request->has('eol')) {
if ($request->filled('eol')) {
$row[] = ($asset->purchase_date!='') ? $asset->present()->eol_date() : '';
}
if ($request->has('order')) {
if ($request->filled('order')) {
$row[] = ($asset->order_number) ? $asset->order_number : '';
}
if ($request->has('supplier')) {
if ($request->filled('supplier')) {
$row[] = ($asset->supplier) ? $asset->supplier->name : '';
}
if ($request->has('location')) {
if ($request->filled('location')) {
$row[] = ($asset->location) ? $asset->location->present()->name() : '';
}
if ($request->has('location_address')) {
if ($request->filled('location_address')) {
$row[] = ($asset->location) ? $asset->location->address : '';
$row[] = ($asset->location) ? $asset->location->address2 : '';
$row[] = ($asset->location) ? $asset->location->city : '';
@@ -588,11 +588,11 @@ class ReportsController extends Controller
$row[] = ($asset->location) ? $asset->location->zip : '';
}
if ($request->has('rtd_location')) {
if ($request->filled('rtd_location')) {
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->present()->name() : '';
}
if ($request->has('rtd_location_address')) {
if ($request->filled('rtd_location_address')) {
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address2 : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->city : '';
@@ -602,12 +602,12 @@ class ReportsController extends Controller
}
if ($request->has('assigned_to')) {
if ($request->filled('assigned_to')) {
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ? $asset->assigned->getFullNameAttribute() : ($asset->assigned ? $asset->assigned->display_name : '');
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ? 'user' : $asset->assignedType();
}
if ($request->has('username')) {
if ($request->filled('username')) {
// Only works if we're checked out to a user, not anything else.
if ($asset->checkedOutToUser()) {
$row[] = ($asset->assignedto) ? $asset->assignedto->username : '';
@@ -616,7 +616,7 @@ class ReportsController extends Controller
}
}
if ($request->has('employee_num')) {
if ($request->filled('employee_num')) {
// Only works if we're checked out to a user, not anything else.
if ($asset->checkedOutToUser()) {
$row[] = ($asset->assignedto) ? $asset->assignedto->employee_num : '';
@@ -625,7 +625,7 @@ class ReportsController extends Controller
}
}
if ($request->has('manager')) {
if ($request->filled('manager')) {
if ($asset->checkedOutToUser()) {
$row[] = (($asset->assignedto) && ($asset->assignedto->manager)) ? $asset->assignedto->manager->present()->fullName : '';
} else {
@@ -634,7 +634,7 @@ class ReportsController extends Controller
}
if ($request->has('department')) {
if ($request->filled('department')) {
if ($asset->checkedOutToUser()) {
$row[] = (($asset->assignedto) && ($asset->assignedto->department)) ? $asset->assignedto->department->name : '';
} else {
@@ -642,55 +642,55 @@ class ReportsController extends Controller
}
}
if ($request->has('status')) {
if ($request->filled('status')) {
$row[] = ($asset->assetstatus) ? $asset->assetstatus->name.' ('.$asset->present()->statusMeta.')' : '';
}
if ($request->has('warranty')) {
if ($request->filled('warranty')) {
$row[] = ($asset->warranty_months) ? $asset->warranty_months : '';
$row[] = $asset->present()->warrantee_expires();
}
if ($request->has('depreciation')) {
if ($request->filled('depreciation')) {
$depreciation = $asset->getDepreciatedValue();
$diff = ($asset->purchase_cost - $depreciation);
$row[] = Helper::formatCurrencyOutput($depreciation);
$row[] = Helper::formatCurrencyOutput($diff);
}
if ($request->has('checkout_date')) {
if ($request->filled('checkout_date')) {
$row[] = ($asset->last_checkout) ? $asset->last_checkout : '';
}
if ($request->has('expected_checkin')) {
if ($request->filled('expected_checkin')) {
$row[] = ($asset->expected_checkin) ? $asset->expected_checkin : '';
}
if ($request->has('created_at')) {
if ($request->filled('created_at')) {
$row[] = ($asset->created_at) ? $asset->created_at : '';
}
if ($request->has('updated_at')) {
if ($request->filled('updated_at')) {
$row[] = ($asset->updated_at) ? $asset->updated_at : '';
}
if ($request->has('last_audit_date')) {
if ($request->filled('last_audit_date')) {
$row[] = ($asset->last_audit_date) ? $asset->last_audit_date : '';
}
if ($request->has('next_audit_date')) {
if ($request->filled('next_audit_date')) {
$row[] = ($asset->next_audit_date) ? $asset->next_audit_date : '';
}
if ($request->has('notes')) {
if ($request->filled('notes')) {
$row[] = ($asset->notes) ? $asset->notes : '';
}
foreach ($customfields as $customfield) {
$column_name = $customfield->db_column_name();
if ($request->has($customfield->db_column_name())) {
if ($request->filled($customfield->db_column_name())) {
$row[] = $asset->$column_name;
}
}
+9 -9
View File
@@ -326,7 +326,7 @@ class SettingsController extends Controller
$setting->modellist_displays = '';
if (($request->has('show_in_model_list')) && (count($request->input('show_in_model_list')) > 0))
if (($request->filled('show_in_model_list')) && (count($request->input('show_in_model_list')) > 0))
{
$setting->modellist_displays = implode(',', $request->input('show_in_model_list'));
}
@@ -495,7 +495,7 @@ class SettingsController extends Controller
$setting->pwd_secure_complexity = '';
if ($request->has('pwd_secure_complexity')) {
if ($request->filled('pwd_secure_complexity')) {
$setting->pwd_secure_complexity = implode('|', $request->input('pwd_secure_complexity'));
}
@@ -794,31 +794,31 @@ class SettingsController extends Controller
if ($request->has('labels_display_name')) {
if ($request->filled('labels_display_name')) {
$setting->labels_display_name = 1;
} else {
$setting->labels_display_name = 0;
}
if ($request->has('labels_display_serial')) {
if ($request->filled('labels_display_serial')) {
$setting->labels_display_serial = 1;
} else {
$setting->labels_display_serial = 0;
}
if ($request->has('labels_display_tag')) {
if ($request->filled('labels_display_tag')) {
$setting->labels_display_tag = 1;
} else {
$setting->labels_display_tag = 0;
}
if ($request->has('labels_display_tag')) {
if ($request->filled('labels_display_tag')) {
$setting->labels_display_tag = 1;
} else {
$setting->labels_display_tag = 0;
}
if ($request->has('labels_display_model')) {
if ($request->filled('labels_display_model')) {
$setting->labels_display_model = 1;
} else {
$setting->labels_display_model = 0;
@@ -907,7 +907,7 @@ class SettingsController extends Controller
public function getBackups()
{
$path = storage_path().'/app/'.config('laravel-backup.backup.name');
$path = storage_path().'/app/'.config('backup.backup.name');
$files = array();
@@ -983,7 +983,7 @@ class SettingsController extends Controller
public function downloadFile($filename = null)
{
if (!config('app.lock_passwords')) {
$path = storage_path().'/app/'.config('laravel-backup.backup.name');
$path = storage_path().'/app/'.config('backup.backup.name');
$file = $path.'/'.$filename;
if (file_exists($file)) {
return Response::download($file);
@@ -78,7 +78,7 @@ class StatuslabelsController extends Controller
// create a new model instance
$statusLabel = new Statuslabel();
if (!$request->has('statuslabel_types')) {
if (!$request->filled('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
@@ -141,7 +141,7 @@ class StatuslabelsController extends Controller
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
if (!$request->has('statuslabel_types')) {
if (!$request->filled('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
+4 -4
View File
@@ -83,7 +83,7 @@ class SuppliersController extends Controller
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/suppliers/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
@@ -159,7 +159,7 @@ class SuppliersController extends Controller
$file_name = $supplier->id.'-'.str_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
Image::make($image->getRealPath())->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(app('suppliers_upload_path').$file_name);
@@ -174,7 +174,7 @@ class SuppliersController extends Controller
try {
unlink(app('suppliers_upload_path').$old_image);
} catch (\Exception $e) {
\Log::error($e);
\Log::info($e);
}
}
@@ -196,7 +196,7 @@ class SuppliersController extends Controller
public function destroy($supplierId)
{
$this->authorize('delete', Supplier::class);
if (is_null($supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances','assets','licenses')->find($supplierId))) {
if (is_null($supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count','assets as assets_count','licenses as licenses_count')->find($supplierId))) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.not_found'));
}
+17 -16
View File
@@ -107,7 +107,7 @@ class UsersController extends Controller
//Username, email, and password need to be handled specially because the need to respect config values on an edit.
$user->email = $data['email'] = e($request->input('email'));
$user->username = $data['username'] = e($request->input('username'));
if ($request->has('password')) {
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
$data['password'] = $request->input('password');
}
@@ -139,13 +139,13 @@ class UsersController extends Controller
if ($user->save()) {
if ($request->has('groups')) {
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
} else {
$user->groups()->sync(array());
}
if (($request->input('email_user') == 1) && ($request->has('email'))) {
if (($request->input('email_user') == 1) && ($request->filled('email'))) {
// Send the credentials through email
$data = array();
$data['email'] = e($request->input('email'));
@@ -263,7 +263,7 @@ class UsersController extends Controller
}
if ($request->has('username')) {
if ($request->filled('username')) {
$user->username = $request->input('username');
}
$user->email = $request->input('email');
@@ -278,6 +278,7 @@ class UsersController extends Controller
$user->activated = $request->input('activated', 0);
$user->jobtitle = $request->input('jobtitle', null);
$user->phone = $request->input('phone');
$user->website = $request->input('website', null);
$user->location_id = $request->input('location_id', null);
$user->company_id = Company::getIdForUser($request->input('company_id', null));
$user->manager_id = $request->input('manager_id', null);
@@ -296,7 +297,7 @@ class UsersController extends Controller
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
// Do we want to update the user password?
if ($request->has('password')) {
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
@@ -389,7 +390,7 @@ class UsersController extends Controller
{
$this->authorize('update', User::class);
if (($request->has('ids')) && (count($request->input('ids')) > 0)) {
if (($request->filled('ids')) && (count($request->input('ids')) > 0)) {
$statuslabel_list = Helper::statusLabelList();
$user_raw_array = array_keys(Input::get('ids'));
$users = User::whereIn('id', $user_raw_array)->with('groups', 'assets', 'licenses', 'accessories')->get();
@@ -415,28 +416,28 @@ class UsersController extends Controller
{
$this->authorize('update', User::class);
if (($request->has('ids')) && (count($request->input('ids')) > 0)) {
if (($request->filled('ids')) && (count($request->input('ids')) > 0)) {
$user_raw_array = $request->input('ids');
$update_array = array();
$manager_conflict = false;
$users = User::whereIn('id', $user_raw_array)->where('id', '!=', Auth::user()->id)->get();
if ($request->has('location_id')) {
if ($request->filled('location_id')) {
$update_array['location_id'] = $request->input('location_id');
}
if ($request->has('department_id')) {
if ($request->filled('department_id')) {
$update_array['department_id'] = $request->input('department_id');
}
if ($request->has('company_id')) {
if ($request->filled('company_id')) {
$update_array['company_id'] = $request->input('company_id');
}
if ($request->has('locale')) {
if ($request->filled('locale')) {
$update_array['locale'] = $request->input('locale');
}
if ($request->has('manager_id')) {
if ($request->filled('manager_id')) {
// Do not allow a manager update if the selected manager is one of the users being
// edited.
@@ -447,7 +448,7 @@ class UsersController extends Controller
}
}
if ($request->has('activated')) {
if ($request->filled('activated')) {
$update_array['activated'] = $request->input('activated');
}
@@ -457,7 +458,7 @@ class UsersController extends Controller
}
// Only sync groups if groups were selected
if ($request->has('groups')) {
if ($request->filled('groups')) {
foreach ($users as $user) {
$user->groups()->sync($request->input('groups'));
}
@@ -489,9 +490,9 @@ class UsersController extends Controller
{
$this->authorize('update', User::class);
if ((!$request->has('ids')) || (count($request->input('ids')) == 0)) {
if ((!$request->filled('ids')) || (count($request->input('ids')) == 0)) {
return redirect()->back()->with('error', 'No users selected');
} elseif ((!$request->has('status_id')) || ($request->input('status_id')=='')) {
} elseif ((!$request->filled('status_id')) || ($request->input('status_id')=='')) {
return redirect()->route('users.index')->with('error', 'No status selected');
} else {
@@ -269,7 +269,7 @@ class ViewAssetsController extends Controller
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
if ($request->has('signature_output')) {
if ($request->filled('signature_output')) {
$path = config('app.private_uploads').'/signatures';
$sig_filename = "siglog-".$findlog->id.'-'.date('Y-m-d-his').".png";
$data_uri = e($request->get('signature_output'));
+11
View File
@@ -6,6 +6,8 @@ use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter;
class EncryptCookies extends BaseEncrypter
{
/**
* The names of the cookies that should not be encrypted.
*
@@ -14,4 +16,13 @@ class EncryptCookies extends BaseEncrypter
protected $except = [
//
];
/**
* Indicates if cookies should be serialized.
*
* @var bool
*/
protected static $serialize = true;
}
+21 -1
View File
@@ -2,10 +2,12 @@
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Models\AssetModel;
use Session;
use Illuminate\Contracts\Validation\Validator;
class AssetRequest extends Request
{
/**
@@ -65,4 +67,22 @@ class AssetRequest extends Request
\Input::flash();
return parent::response($errors);
}
/**
* Handle a failed validation attempt.
*
* public function json($data = [], $status = 200, array $headers = [], $options = 0)
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator)
{
return response()->json([
'message' => 'The given data is invalid',
'errors' => $validator->errors()
], 422);
}
}
+14
View File
@@ -43,6 +43,20 @@ class ItemImportRequest extends FormRequest
$import->save();
$fieldMappings=[];
if ($import->field_map) {
// This checks to make sure the field header has been mapped.
// If it hasn't been, it will throw an array_flip error
foreach ($import->field_map as $field => $fieldValue) {
$errorMessage = null;
if(is_null($fieldValue)){
$errorMessage = 'All import fields must be mapped.';
$this->errorCallback($import, $field, $errorMessage);
return $this->errors;
}
}
// We submit as csv field: column, but the importer is happier if we flip it here.
$fieldMappings = array_change_key_case(array_flip($import->field_map), CASE_LOWER);
// dd($fieldMappings);
@@ -26,6 +26,18 @@ class ActionlogsTransformer
if ($actionlog->filename!='') {
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
}
// This is necessary since we can't escape special characters within a JSON object
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
$meta_array = json_decode($actionlog->log_meta);
foreach ($meta_array as $key => $value) {
foreach ($value as $meta_key => $meta_value) {
$clean_meta[$key][$meta_key] = e($meta_value);
}
}
}
$array = [
'id' => (int) $actionlog->id,
'icon' => $icon,
@@ -64,7 +76,7 @@ class ActionlogsTransformer
'note' => ($actionlog->note) ? e($actionlog->note): null,
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
'log_meta' => ($actionlog->log_meta) ? json_decode($actionlog->log_meta): null,
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
];
+4 -1
View File
@@ -24,7 +24,7 @@ class UsersTransformer
$array = [
'id' => (int) $user->id,
'avatar' => e($user->present()->gravatar),
'name' => e($user->first_name).' '.($user->last_name),
'name' => e($user->first_name).' '.e($user->last_name),
'first_name' => e($user->first_name),
'last_name' => e($user->last_name),
'username' => e($user->username),
@@ -35,6 +35,7 @@ class UsersTransformer
] : null,
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
'phone' => ($user->phone) ? e($user->phone) : null,
'website' => ($user->website) ? e($user->website) : null,
'address' => ($user->address) ? e($user->address) : null,
'city' => ($user->city) ? e($user->city) : null,
'state' => ($user->state) ? e($user->state) : null,
@@ -53,6 +54,8 @@ class UsersTransformer
'permissions' => $user->decodePermissions(),
'activated' => ($user->activated =='1') ? true : false,
'two_factor_activated' => ($user->two_factor_active()) ? true : false,
'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false,
'assets_count' => (int) $user->assets_count,
'licenses_count' => (int) $user->licenses_count,
'accessories_count' => (int) $user->accessories_count,
+2 -1
View File
@@ -120,7 +120,8 @@ abstract class Importer
public function import()
{
$headerRow = $this->csv->fetchOne();
$results = $this->normalizeInputArray($this->csv->fetchAssoc());
$this->csv->setHeaderOffset(0); //explicitly sets the CSV document header record
$results = $this->normalizeInputArray($this->csv->getRecords($headerRow));
$this->populateCustomFields($headerRow);
+78 -3
View File
@@ -796,6 +796,83 @@ class Asset extends Depreciable
});
}
/**
* Query builder scope for Assets that are due for auditing, based on the assets.next_audit_date
* and settings.audit_warning_days.
*
* This is/will be used in the artisan command snipeit:upcoming-audits and also
* for an upcoming API call for retrieving a report on assets that will need to be audited.
*
* Due for audit soon:
* next_audit_date greater than or equal to now (must be in the future)
* and (next_audit_date - threshold days) <= now ()
*
* Example:
* next_audit_date = May 4, 2025
* threshold for alerts = 30 days
* now = May 4, 2019
*
* @author A. Gianotto <snipe@snipe.net>
* @since v4.6.16
* @param Setting $settings
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeDueForAudit($query, $settings)
{
return $query->whereNotNull('assets.next_audit_date')
->where('assets.next_audit_date', '>=', Carbon::now())
->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'")
->where('assets.archived', '=', 0)
->NotArchived();
}
/**
* Query builder scope for Assets that are OVERDUE for auditing, based on the assets.next_audit_date
* and settings.audit_warning_days. It checks to see if assets.next audit_date is before now
*
* This is/will be used in the artisan command snipeit:upcoming-audits and also
* for an upcoming API call for retrieving a report on overdue assets.
*
* @author A. Gianotto <snipe@snipe.net>
* @since v4.6.16
* @param Setting $settings
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOverdueForAudit($query)
{
return $query->whereNotNull('assets.next_audit_date')
->where('assets.next_audit_date', '<', Carbon::now())
->where('assets.archived', '=', 0)
->NotArchived();
}
/**
* Query builder scope for Assets that are due for auditing OR overdue, based on the assets.next_audit_date
* and settings.audit_warning_days.
*
* This is/will be used in the artisan command snipeit:upcoming-audits and also
* for an upcoming API call for retrieving a report on assets that will need to be audited.
*
* @author A. Gianotto <snipe@snipe.net>
* @since v4.6.16
* @param Setting $settings
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeDueOrOverdueForAudit($query, $settings)
{
return $query->whereNotNull('assets.next_audit_date')
->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'")
->where('assets.archived', '=', 0)
->NotArchived();
}
/**
* Query builder scope for Archived assets
*
@@ -961,9 +1038,7 @@ class Asset extends Depreciable
->orWhere('assets.order_number', 'LIKE', '%'.$search.'%')
->orWhere('assets.notes', 'LIKE', '%'.$search.'%');
}
foreach (CustomField::all() as $field) {
$query->orWhere('assets.'.$field->db_column_name(), 'LIKE', "%$search%");
}
})->withTrashed()->whereNull("assets.deleted_at"); //workaround for laravel bug
}
+1 -1
View File
@@ -76,7 +76,7 @@ class Consumable extends SnipeModel
*
* @var array
*/
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date'];
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date', 'item_no'];
/**
* The relations and their attributes that should be included when searching the model.
-1
View File
@@ -26,7 +26,6 @@ class Department extends SnipeModel
protected $rules = [
'name' => 'required|max:255',
'user_id' => 'nullable|exists:users,id',
'location_id' => 'numeric|nullable',
'company_id' => 'numeric|nullable',
'manager_id' => 'numeric|nullable',
+77 -5
View File
@@ -69,6 +69,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
'email' => 'email|nullable',
'password' => 'required|min:6',
'locale' => 'max:10|nullable',
'website' => 'url|nullable',
];
use Searchable;
@@ -389,7 +390,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
}
/**
* Check whether two-factor authorization is required and the user has activated it
* Check whether two-factor authorization is requiredfor this user
*
* 0 = 2FA disabled
* 1 = 2FA optional
* 2 = 2FA universally required
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
@@ -398,10 +403,45 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
*/
public function two_factor_active () {
if (Setting::getSettings()->two_factor_enabled !='0') {
if (($this->two_factor_optin =='1') && ($this->two_factor_enrolled)) {
return true;
}
// If the 2FA is optional and the user has opted in
if ((Setting::getSettings()->two_factor_enabled =='1') && ($this->two_factor_optin =='1'))
{
return true;
}
// If the 2FA is required for everyone so is implicitly active
elseif (Setting::getSettings()->two_factor_enabled =='2')
{
return true;
}
return false;
}
/**
* Check whether two-factor authorization is required and the user has activated it
* and enrolled a device
*
* 0 = 2FA disabled
* 1 = 2FA optional
* 2 = 2FA universally required
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.6.14]
*
* @return bool
*/
public function two_factor_active_and_enrolled () {
// If the 2FA is optional and the user has opted in and is enrolled
if ((Setting::getSettings()->two_factor_enabled =='1') && ($this->two_factor_optin =='1') && ($this->two_factor_enrolled =='1'))
{
return true;
}
// If the 2FA is required for everyone and the user has enrolled
elseif ((Setting::getSettings()->two_factor_enabled =='2') && ($this->two_factor_enrolled))
{
return true;
}
return false;
@@ -413,6 +453,25 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
return json_decode($this->permissions, true);
}
/**
* Query builder scope to search user by name with spaces in it.
* We don't use the advancedTextSearch() scope because that searches
* all of the relations as well, which is more than what we need.
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param array $terms The search terms
* @return \Illuminate\Database\Query\Builder
*/
public function scopeSimpleNameSearch($query, $search) {
$query = $query->where('first_name', 'LIKE', '%'.$search.'%')
->orWhere('last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$search%", "%$search%"]);
return $query;
}
/**
* Run additional, advanced searches.
*
@@ -490,4 +549,17 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
{
return $query->leftJoin('departments as departments_users', 'users.department_id', '=', 'departments_users.id')->orderBy('departments_users.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCompany($query, $order)
{
return $query->leftJoin('companies as companies_user', 'users.company_id', '=', 'companies_user.id')->orderBy('companies_user.name', $order);
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Notifications;
use App\Models\Setting;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class SendUpcomingAuditNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($params, $threshold)
{
$this->assets = $params;
$this->threshold = $threshold;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return $notifyBy = ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits',
[
'assets' => $this->assets,
'threshold' => $this->threshold,
])
->subject(trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count(), 'threshold' => $this->threshold]));
return $message;
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
+19 -8
View File
@@ -13,16 +13,27 @@ class LicensePolicy extends CheckoutablePermissionsPolicy
return 'licenses';
}
/**
* Determine whether the user can view license keys
*
* @param \App\Models\User $user
* @param \App\Models\License $license
* @return mixed
*/
/**
* Determine whether the user can view license keys.
* This gets a little tricky, UX/logic-wise. If a user has the ability
* to create a license (which requires a product key), shouldn't they
* have the ability to see the product key as well?
*
* Example: I create the license, realize I need to change
* something (maybe I got the product key wrong), and now I can never
* see/edit that product key.
*
* @see https://github.com/snipe/snipe-it/issues/6956
* @param \App\Models\User $user
* @param \App\Models\License $license
* @return mixed
*/
public function viewKeys(User $user, License $license = null)
{
return $user->hasAccess('licenses.keys');
if ($user->hasAccess('licenses.keys') || $user->hasAccess('licenses.create') || $user->hasAccess('licenses.edit')) {
return true;
}
return false;
}
}
+7 -5
View File
@@ -53,7 +53,7 @@ abstract class SnipePermissionsPolicy
/**
* Determine whether the user can view the accessory.
*
* @param \App\User $user
* @param \App\Models\User $user
* @return mixed
*/
public function view(User $user, $item = null)
@@ -64,7 +64,7 @@ abstract class SnipePermissionsPolicy
/**
* Determine whether the user can create accessories.
*
* @param \App\User $user
* @param \App\Models\User $user
* @return mixed
*/
public function create(User $user)
@@ -75,7 +75,7 @@ abstract class SnipePermissionsPolicy
/**
* Determine whether the user can update the accessory.
*
* @param \App\User $user
* @param \App\Models\User $user
* @return mixed
*/
public function update(User $user, $item = null)
@@ -86,7 +86,7 @@ abstract class SnipePermissionsPolicy
/**
* Determine whether the user can delete the accessory.
*
* @param \App\User $user
* @param \App\Models\User $user
* @return mixed
*/
public function delete(User $user, $item = null)
@@ -97,11 +97,13 @@ abstract class SnipePermissionsPolicy
/**
* Determine whether the user can manage the accessory.
*
* @param \App\User $user
* @param \App\Models\User $user
* @return mixed
*/
public function manage(User $user, $item = null)
{
return $user->hasAccess($this->columnName().'.edit');
}
}
+273
View File
@@ -0,0 +1,273 @@
<?php
namespace App\Presenters;
use App\Models\CustomField;
use DateTime;
/**
* Class AssetPresenter
* @package App\Presenters
*/
class AssetAuditPresenter extends Presenter
{
/**
* Json Column Layout for bootstrap table
* @return string
*/
public static function dataTableLayout()
{
$layout = [
[
"field" => "id",
"searchable" => false,
"sortable" => true,
"switchable" => true,
"title" => trans('general.id'),
"visible" => false
], [
"field" => "company",
"searchable" => true,
"sortable" => true,
"switchable" => true,
"title" => trans('general.company'),
"visible" => false,
"formatter" => 'assetCompanyObjFilterFormatter'
], [
"field" => "name",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.name'),
"visible" => true,
"formatter" => "hardwareLinkFormatter"
], [
"field" => "image",
"searchable" => false,
"sortable" => true,
"switchable" => true,
"title" => trans('admin/hardware/table.image'),
"visible" => false,
"formatter" => "imageFormatter"
], [
"field" => "asset_tag",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.asset_tag'),
"visible" => true,
"formatter" => "hardwareLinkFormatter"
], [
"field" => "serial",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.serial'),
"visible" => true,
"formatter" => "hardwareLinkFormatter"
], [
"field" => "model",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.model'),
"visible" => true,
"formatter" => "modelsLinkObjFormatter"
], [
"field" => "model_number",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/models/table.modelnumber'),
"visible" => false
], [
"field" => "category",
"searchable" => true,
"sortable" => true,
"title" => trans('general.category'),
"visible" => false,
"formatter" => "categoriesLinkObjFormatter"
], [
"field" => "status_label",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.status'),
"visible" => true,
"formatter" => "statuslabelsLinkObjFormatter"
], [
"field" => "assigned_to",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.checkedout_to'),
"visible" => true,
"formatter" => "polymorphicItemFormatter"
], [
"field" => "location",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/table.location'),
"visible" => true,
"formatter" => "deployedLocationFormatter"
], [
"field" => "rtd_location",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/hardware/form.default_location'),
"visible" => false,
"formatter" => "deployedLocationFormatter"
], [
"field" => "manufacturer",
"searchable" => true,
"sortable" => true,
"title" => trans('general.manufacturer'),
"visible" => false,
"formatter" => "manufacturersLinkObjFormatter"
], [
"field" => "purchase_date",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('general.purchase_date'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "purchase_cost",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('general.purchase_cost'),
"footerFormatter" => 'sumFormatter',
], [
"field" => "order_number",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('general.order_number'),
'formatter' => "orderNumberObjFilterFormatter"
], [
"field" => "eol",
"searchable" => false,
"sortable" => false,
"visible" => false,
"title" => trans('general.eol'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "warranty_months",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('admin/hardware/form.warranty')
],[
"field" => "warranty_expires",
"searchable" => false,
"sortable" => false,
"visible" => false,
"title" => trans('admin/hardware/form.warranty_expires'),
"formatter" => "dateDisplayFormatter"
],[
"field" => "notes",
"searchable" => true,
"sortable" => true,
"visible" => false,
"title" => trans('general.notes'),
], [
"field" => "checkout_counter",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.checkouts_count')
],[
"field" => "checkin_counter",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.checkins_count')
], [
"field" => "requests_counter",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.user_requests_count')
], [
"field" => "created_at",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.created_at'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "updated_at",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.updated_at'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "last_checkout",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('admin/hardware/table.checkout_date'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "expected_checkin",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('admin/hardware/form.expected_checkin'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "last_audit_date",
"searchable" => false,
"sortable" => true,
"visible" => true,
"title" => trans('general.last_audit'),
"formatter" => "dateDisplayFormatter"
], [
"field" => "next_audit_date",
"searchable" => false,
"sortable" => true,
"visible" => true,
"title" => trans('general.next_audit_date'),
"formatter" => "dateDisplayFormatter"
],
];
// This looks complicated, but we have to confirm that the custom fields exist in custom fieldsets
// *and* those fieldsets are associated with models, otherwise we'll trigger
// javascript errors on the bootstrap tables side of things, since we're asking for properties
// on fields that will never be passed through the REST API since they're not associated with
// models. We only pass the fieldsets that pertain to each asset (via their model) so that we
// don't junk up the REST API with tons of custom fields that don't apply
$fields = CustomField::whereHas('fieldset', function ($query) {
$query->whereHas('models');
})->get();
foreach ($fields as $field) {
$layout[] = [
"field" => 'custom_fields.'.$field->convertUnicodeDbSlug(),
"searchable" => true,
"sortable" => true,
"visible" => false,
"switchable" => true,
"title" => ($field->field_encrypted=='1') ?'<i class="fa fa-lock"></i> '.e($field->name) : e($field->name),
"formatter" => "customFieldsFormatter"
];
}
$layout[] = [
"field" => "actions",
"searchable" => false,
"sortable" => false,
"switchable" => false,
"title" => trans('table.actions'),
"formatter" => "hardwareAuditFormatter",
];
return json_encode($layout);
}
}
+8 -4
View File
@@ -391,7 +391,7 @@ class AssetPresenter extends Presenter
public function eol_date()
{
if (( $this->purchase_date ) && ( $this->model )) {
if (( $this->purchase_date ) && ( $this->model ) && ($this->model->model->eol) ) {
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->model->model->eol . ' months'));
return date_format($date, 'Y-m-d');
@@ -492,9 +492,13 @@ class AssetPresenter extends Presenter
*/
public function warrantee_expires()
{
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->warranty_months . ' months'));
return date_format($date, 'Y-m-d');
if (($this->purchase_date) && ($this->warranty_months)) {
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->warranty_months . ' months'));
return date_format($date, 'Y-m-d');
}
return false;
}
/**
+3 -3
View File
@@ -226,14 +226,14 @@ class UserPresenter extends Presenter
[
"field" => "two_factor_enrolled",
"searchable" => false,
"sortable" => false,
"sortable" => true,
"switchable" => true,
"title" => trans('admin/users/general.two_factor_enrolled'),
"visible" => false,
'formatter' => 'trueFalseFormatter'
],
[
"field" => "two_factor_active",
"field" => "two_factor_activated",
"searchable" => false,
"sortable" => false,
"switchable" => true,
@@ -246,7 +246,7 @@ class UserPresenter extends Presenter
"searchable" => false,
"sortable" => true,
"switchable" => true,
"title" => trans('general.activated'),
"title" => trans('general.login_enabled'),
"visible" => true,
'formatter' => 'trueFalseFormatter'
],
+8
View File
@@ -113,6 +113,14 @@ class AuthServiceProvider extends ServiceProvider
});
// Can the user import CSVs?
Gate::define('import', function ($user) {
if ($user->hasAccess('import') ) {
return true;
}
});
# -----------------------------------------
# Reports
# -----------------------------------------
+28
View File
@@ -111,6 +111,34 @@ class SettingsServiceProvider extends ServiceProvider
return url('/').'/uploads/companies/';
});
// Accessories paths and URLs
\App::singleton('accessories_upload_path', function(){
return public_path('/uploads/accessories/');
});
\App::singleton('accessories_upload_url', function(){
return url('/').'/uploads/accessories/';
});
// Consumables paths and URLs
\App::singleton('consumables_upload_path', function(){
return public_path('/uploads/consumables/');
});
\App::singleton('consumables_upload_url', function(){
return url('/').'/uploads/consumables/';
});
// Components paths and URLs
\App::singleton('components_upload_path', function(){
return public_path('/uploads/components/');
});
\App::singleton('components_upload_url', function(){
return url('/').'/uploads/components/';
});
// Set the monetary locale to the configured locale to make helper::parseFloat work.
+30 -22
View File
@@ -5,43 +5,47 @@
"license": "AGPL-3.0-or-later",
"type": "project",
"require": {
"php": ">=5.6.4",
"barryvdh/laravel-debugbar": "^2.4",
"doctrine/cache": "^1.6",
"doctrine/common": "^2.7",
"doctrine/dbal": "^2.5.13",
"doctrine/inflector": "1.1.*",
"doctrine/instantiator": "1.0.*",
"php": ">=7.1.2",
"barryvdh/laravel-debugbar": "^3.2",
"doctrine/cache": "^1.8",
"doctrine/common": "^2.10",
"doctrine/dbal": "2.9.0",
"doctrine/inflector": "^1.3",
"doctrine/instantiator": "^1.2",
"eduardokum/laravel-mail-auto-embed": "^1.0",
"erusev/parsedown": "^1.6",
"fideloper/proxy": "^3.3",
"intervention/image": "^2.3",
"erusev/parsedown": "^1.7",
"fideloper/proxy": "^4.1",
"guzzlehttp/guzzle": "^6.3",
"intervention/image": "^2.4",
"javiereguiluz/easyslugger": "^1.0",
"laravel/framework": "5.4.35",
"laravel/passport": "^3.0",
"laravel/framework": "5.5.*",
"laravel/passport": "4.*",
"laravel/tinker": "^1.0",
"laravelcollective/html": "^5.3",
"league/csv": "^8.1",
"laravelcollective/html": "^5.5",
"league/csv": "^9.2",
"maknz/slack": "^1.7",
"neitanod/forceutf8": "^2.0",
"patchwork/utf8": "~1.2",
"patchwork/utf8": "^1.3",
"phpdocumentor/reflection-docblock": "3.2.2",
"phpspec/prophecy": "1.6.2",
"pragmarx/google2fa": "^1.0",
"phpspec/prophecy": "^1.8",
"pragmarx/google2fa": "^5.0",
"pragmarx/google2fa-laravel": "^1.0",
"predis/predis": "^1.1",
"rollbar/rollbar-laravel": "2.4.1",
"rollbar/rollbar-laravel": "^4.0",
"schuppo/password-strength": "~1.5",
"spatie/laravel-backup": "3.11.0",
"spatie/laravel-backup": "^5.12",
"tecnickcom/tc-lib-barcode": "^1.15",
"tightenco/ziggy": "^0.4.1",
"tightenco/ziggy": "^0.7.1",
"unicodeveloper/laravel-password": "^1.0",
"watson/validating": "^3.0"
},
"require-dev": {
"codeception/codeception": "2.3.6",
"filp/whoops": "~2.0",
"fzaninotto/faker": "~1.4",
"phpunit/php-token-stream": "1.4.11",
"phpunit/phpunit": "~5.7",
"phpunit/phpunit": "~6.0",
"roave/security-advisories": "dev-master",
"squizlabs/php_codesniffer": "*",
"symfony/css-selector": "3.1.*",
"symfony/dom-crawler": "3.1.*"
@@ -66,6 +70,10 @@
],
"post-create-project-cmd": [
"php artisan key:generate"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover"
]
},
"config": {
@@ -74,7 +82,7 @@
"optimize-autoloader": true,
"process-timeout":3000,
"platform": {
"php": "5.6.4"
"php": "7.1.2"
}
}
Generated
+2080 -637
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -286,12 +286,11 @@ return [
* Package Service Providers...
*/
Barryvdh\Debugbar\ServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
Spatie\Backup\BackupServiceProvider::class,
Fideloper\Proxy\TrustedProxyServiceProvider::class,
PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class,
PragmaRX\Google2FALaravel\ServiceProvider::class,
Laravel\Passport\PassportServiceProvider::class,
Laravel\Tinker\TinkerServiceProvider::class,
Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class,
+222
View File
@@ -0,0 +1,222 @@
<?php
// This is janky, but necessary to figure out whether to include the .env in the backup
$included_dirs = [
base_path('public/uploads'),
base_path('config'),
base_path('storage/private_uploads'),
base_path('storage/oauth-private.key'),
base_path('storage/oauth-public.key'),
];
if (env('BACKUP_ENV')=='true') {
$included_dirs[] = base_path('.env');
}
return [
'backup' => [
/*
* The name of this application. You can use this name to monitor
* the backups.
*/
'name' => 'backups',
'source' => [
'files' => [
/*
* The list of directories and files that will be included in the backup.
*/
'include' => $included_dirs,
/*
* These directories and files will be excluded from the backup.
*
* Directories used by the backup process will automatically be excluded.
*/
'exclude' => [
base_path('vendor'),
base_path('node_modules'),
],
/*
* Determines if symlinks should be followed.
*/
'followLinks' => false,
],
/*
* The names of the connections to the databases that should be backed up
* MySQL, PostgreSQL, SQLite and Mongo databases are supported.
*
* The content of the database dump may be customized for each connection
* by adding a 'dump' key to the connection settings in config/database.php.
* E.g.
* 'mysql' => [
* ...
* 'dump' => [
* 'excludeTables' => [
* 'table_to_exclude_from_backup',
* 'another_table_to_exclude'
* ]
* ]
* ],
*
* For a complete list of available customization options, see https://github.com/spatie/db-dumper
*/
'databases' => [
'mysql',
],
],
/*
* The database dump can be compressed to decrease diskspace usage.
*
* Out of the box Laravel-backup supplies
* Spatie\DbDumper\Compressors\GzipCompressor::class.
*
* You can also create custom compressor. More info on that here:
* https://github.com/spatie/db-dumper#using-compression
*
* If you do not want any compressor at all, set it to null.
*/
'database_dump_compressor' => null,
'destination' => [
/*
* The filename prefix used for the backup zip file.
*/
'filename_prefix' => 'snipe-it-',
/*
* The disk names on which the backups will be stored.
*/
'disks' => [
'local',
],
],
/*
* The directory where the temporary files will be stored.
*/
'temporary_directory' => storage_path('app/backup-temp'),
],
/*
* You can get notified when specific events occur. Out of the box you can use 'mail' and 'slack'.
* For Slack you need to install guzzlehttp/guzzle.
*
* You can also use your own notification classes, just make sure the class is named after one of
* the `Spatie\Backup\Events` classes.
*/
'notifications' => [
'notifications' => [
\Spatie\Backup\Notifications\Notifications\BackupHasFailed::class => ['mail'],
\Spatie\Backup\Notifications\Notifications\UnhealthyBackupWasFound::class => ['mail'],
\Spatie\Backup\Notifications\Notifications\CleanupHasFailed::class => ['mail'],
\Spatie\Backup\Notifications\Notifications\BackupWasSuccessful::class => ['mail'],
\Spatie\Backup\Notifications\Notifications\HealthyBackupWasFound::class => ['mail'],
\Spatie\Backup\Notifications\Notifications\CleanupWasSuccessful::class => ['mail'],
],
/*
* Here you can specify the notifiable to which the notifications should be sent. The default
* notifiable will use the variables specified in this config file.
*/
'notifiable' => \Spatie\Backup\Notifications\Notifiable::class,
'mail' => [
'to' => 'your@example.com',
],
'slack' => [
'webhook_url' => '',
/*
* If this is set to null the default channel of the webhook will be used.
*/
'channel' => null,
'username' => null,
'icon' => null,
],
],
/*
* Here you can specify which backups should be monitored.
* If a backup does not meet the specified requirements the
* UnHealthyBackupWasFound event will be fired.
*/
'monitorBackups' => [
[
'name' => config('app.name'),
'disks' => ['local'],
'newestBackupsShouldNotBeOlderThanDays' => 1,
'storageUsedMayNotBeHigherThanMegabytes' => 5000,
],
/*
[
'name' => 'name of the second app',
'disks' => ['local', 's3'],
'newestBackupsShouldNotBeOlderThanDays' => 1,
'storageUsedMayNotBeHigherThanMegabytes' => 5000,
],
*/
],
'cleanup' => [
/*
* The strategy that will be used to cleanup old backups. The default strategy
* will keep all backups for a certain amount of days. After that period only
* a daily backup will be kept. After that period only weekly backups will
* be kept and so on.
*
* No matter how you configure it the default strategy will never
* delete the newest backup.
*/
'strategy' => \Spatie\Backup\Tasks\Cleanup\Strategies\DefaultStrategy::class,
'defaultStrategy' => [
/*
* The number of days for which backups must be kept.
*/
'keepAllBackupsForDays' => 7,
/*
* The number of days for which daily backups must be kept.
*/
'keepDailyBackupsForDays' => 16,
/*
* The number of weeks for which one weekly backup must be kept.
*/
'keepWeeklyBackupsForWeeks' => 8,
/*
* The number of months for which one monthly backup must be kept.
*/
'keepMonthlyBackupsForMonths' => 4,
/*
* The number of years for which one yearly backup must be kept.
*/
'keepYearlyBackupsForYears' => 2,
/*
* After cleaning up the backups remove the oldest backup until
* this amount of megabytes has been reached.
*/
'deleteOldestBackupsWhenUsingMoreMegabytesThan' => 5000,
],
],
];
+7 -3
View File
@@ -80,9 +80,13 @@ return [
'strict' => false,
'engine' => 'InnoDB',
'unix_socket' => env('DB_SOCKET',''),
'dump_command_path' => env('DB_DUMP_PATH', '/usr/local/bin'), // only the path, so without 'mysqldump'
'dump_command_timeout' => 60 * 5, // 5 minute timeout
'dump_using_single_transaction' => true, // perform dump using a single transaction
'dump' => [
'dump_binary_path' => env('DB_DUMP_PATH', '/usr/local/bin'), // only the path, so without 'mysqldump'
'use_single_transaction',
'timeout' => 60 * 5, // 5 minute timeout
//'exclude_tables' => ['table1', 'table2'],
//'add_extra_option' => '--optionname=optionvalue',
],
'options' => (env('DB_SSL')) ? [
PDO::MYSQL_ATTR_SSL_KEY => env('DB_SSL_KEY_PATH'), // /path/to/key.pem
PDO::MYSQL_ATTR_SSL_CERT => env('DB_SSL_CERT_PATH'), // /path/to/cert.pem
-191
View File
@@ -1,191 +0,0 @@
<?php
/*
|--------------------------------------------------------------------------
| DO NOT EDIT THIS FILE DIRECTLY.
|--------------------------------------------------------------------------
| This file reads from your .env configuration file and should not
| be modified directly.
*/
return [
'backup' => [
/*
* The name of this application. You can use this name to monitor
* the backups.
*/
'name' => 'backups',
'source' => [
'files' => [
/*
* The list of directories that should be part of the backup. You can
* specify individual files as well.
*/
'include' => [
base_path('public/uploads'),
base_path('config'),
base_path('storage/private_uploads'),
base_path('storage/oauth-private.key'),
base_path('storage/oauth-public.key'),
(env('BACKUP_ENV')=='true') ? base_path('.env') : '',
],
/*
* These directories will be excluded from the backup.
* You can specify individual files as well.
*/
'exclude' => [
// base_path('vendor'),
// base_path('node_modules'),
],
/*
* Determines if symlinks should be followed.
*/
'followLinks' => false,
],
/*
* The names of the connections to the databases that should be part of the backup.
* Currently only MySQL- and PostgreSQL-databases are supported.
*/
'databases' => [
'mysql',
],
],
'destination' => [
/*
* The disk names on which the backups will be stored.
*/
'disks' => [
'local',
],
],
],
'cleanup' => [
/*
* The strategy that will be used to cleanup old backups.
* The youngest backup will never be deleted.
*/
'strategy' => \Spatie\Backup\Tasks\Cleanup\Strategies\DefaultStrategy::class,
'defaultStrategy' => [
/*
* The amount of days that all daily backups must be kept.
*/
'keepAllBackupsForDays' => 7,
/*
* The amount of days that all daily backups must be kept.
*/
'keepDailyBackupsForDays' => 16,
/*
* The amount of weeks of which one weekly backup must be kept.
*/
'keepWeeklyBackupsForWeeks' => 8,
/*
* The amount of months of which one monthly backup must be kept.
*/
'keepMonthlyBackupsForMonths' => 4,
/*
* The amount of years of which one yearly backup must be kept
*/
'keepYearlyBackupsForYears' => 2,
/*
* After cleaning up the backups remove the oldest backup until
* this amount of megabytes has been reached.
*/
'deleteOldestBackupsWhenUsingMoreMegabytesThan' => 5000
]
],
/*
* In this array you can specify which backups should be monitored.
* If a backup does not meet the specified requirements the
* UnHealthyBackupWasFound-event will be fired.
*/
'monitorBackups' => [
[
'name' => 'backups',
'disks' => ['local'],
'newestBackupsShouldNotBeOlderThanDays' => 1,
'storageUsedMayNotBeHigherThanMegabytes' => 5000,
],
/*
[
'name' => 'name of the second app',
'disks' => ['local', 's3'],
'newestBackupsShouldNotBeOlderThanDays' => 1,
'storageUsedMayNotBeHigherThanMegabytes' => 5000,
],
*/
],
'notifications' => [
/*
* This class will be used to send all notifications.
*/
'handler' => Spatie\Backup\Notifications\Notifier::class,
/*
* Here you can specify the ways you want to be notified when certain
* events take place. Possible values are "log", "mail", "slack" and "pushover".
*
* Slack requires the installation of the maknz/slack package.
*/
'events' => [
'whenBackupWasSuccessful' => ['log'],
'whenCleanupWasSuccessful' => ['log'],
'whenHealthyBackupWasFound' => ['log'],
'whenBackupHasFailed' => ['log'],
'whenCleanupHasFailed' => ['log'],
'whenUnhealthyBackupWasFound' => ['log'],
],
/*
* Here you can specify how emails should be sent.
*/
'mail' => [
'from' => env('MAIL_FROM_ADDR', 'your@email.com'),
'to' => env('MAIL_FROM_ADDR', 'your@email.com'),
],
/*
* Here you can specify how messages should be sent to Slack.
*/
'slack' => [
'channel' => '#backups',
'username' => 'Backup bot',
'icon' => ':robot:',
],
/*
* Here you can specify how messages should be sent to Pushover.
*/
'pushover' => [
'token' => env('PUSHOVER_APP_TOKEN'),
'user' => env('PUSHOVER_USER_KEY'),
'sounds' => [
'success' => env('PUSHOVER_SOUND_SUCCESS','pushover'),
'error' => env('PUSHOVER_SOUND_ERROR','siren'),
],
],
]
];
+9
View File
@@ -27,6 +27,15 @@ return array(
)
),
'CSV Import' => array(
array(
'permission' => 'import',
'label' => '',
'note' => 'This will allow users to import even if access to users, assets, etc is denied elsewhere.',
'display' => true,
)
),
'Reports' => array(
array(
'permission' => 'reports.view',
+5 -5
View File
@@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v4.6.12',
'full_app_version' => 'v4.6.12 - build 3982-gd687e1d76',
'build_version' => '3982',
'app_version' => 'v4.7.2',
'full_app_version' => 'v4.7.2 - build 4037',
'build_version' => '4037',
'prerelease_version' => '',
'hash_version' => 'gd687e1d76',
'full_hash' => 'v4.6.12-1-gd687e1d76',
'hash_version' => '',
'full_hash' => 'v4.7.2',
'branch' => 'master',
);
@@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class MakeSerialNullable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$platform = Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('enum', 'string');
Schema::table('assets', function (Blueprint $table) {
$table->string('serial')->nullable()->default(null)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
@@ -0,0 +1,64 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class MakeFieldsNullableForIntegrity extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('locations', function (Blueprint $table) {
$table->string('city')->nullable()->default(null)->change();
$table->string('state')->nullable()->default(null)->change();
$table->string('country')->nullable()->default(null)->change();
$table->integer('user_id')->nullable()->default(null)->change();
$table->string('address')->nullable()->default(null)->change();
$table->string('address2')->nullable()->default(null)->change();
});
Schema::table('users', function (Blueprint $table) {
$table->string('last_name')->nullable()->default(null)->change();
});
Schema::table('suppliers', function (Blueprint $table) {
$table->integer('user_id')->nullable()->default(null)->change();
});
Schema::table('status_labels', function (Blueprint $table) {
$table->integer('user_id')->nullable()->default(null)->change();
});
Schema::table('models', function (Blueprint $table) {
$table->integer('user_id')->nullable()->default(null)->change();
$table->integer('manufacturer_id')->nullable()->default(null)->change();
$table->integer('category_id')->nullable()->default(null)->change();
});
Schema::table('licenses', function (Blueprint $table) {
$table->integer('user_id')->nullable()->default(null)->change();
$table->boolean('maintained')->nullable()->default(null)->change();
});
Schema::table('depreciations', function (Blueprint $table) {
$table->integer('user_id')->nullable()->default(null)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
+3
View File
@@ -43,5 +43,8 @@ class DatabaseSeeder extends Seeder
\Log::info($output);
Model::reguard();
DB::table('imports')->truncate();
}
}
+2 -3
View File
@@ -5,7 +5,7 @@ if [ -z "$APP_KEY" ]
then
echo "Please re-run this container with an environment variable \$APP_KEY"
echo "An example APP_KEY you could use is: "
php artisan key:generate --show
/var/www/html/artisan key:generate --show
exit
fi
@@ -47,5 +47,4 @@ then
cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
fi
. /etc/apache2/envvars
exec apache2 -DNO_DETACH < /dev/null
exec supervisord -c /supervisord.conf
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env python
# A supervisor event listener which terminates supervisord if any of its child
# processes enter the FATAL state.
# https://stackoverflow.com/a/37527488/119527
import os
import signal
from supervisor import childutils
def main():
while True:
headers, payload = childutils.listener.wait()
childutils.listener.ok()
if headers['eventname'] != 'PROCESS_STATE_FATAL':
continue
os.kill(os.getppid(), signal.SIGTERM)
if __name__ == "__main__":
main()
+27
View File
@@ -0,0 +1,27 @@
[supervisord]
nodaemon=true
[program:apache]
; https://advancedweb.hu/2018/07/03/supervisor_docker/
command=apache2ctl -DFOREGROUND
killasgroup=true
stopasgroup=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:run_schedule]
; Simply run the Laravel command scheduler every minute
command=/bin/bash -c "while true; do /var/www/html/artisan schedule:run; sleep 1m; done"
user=docker
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
; https://stackoverflow.com/a/37527488/119527
[eventlistener:exit_on_any_fatal]
command=supervisor-exit-event-listener
events=PROCESS_STATE_FATAL
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+8046 -26
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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