Compare commits

...

459 Commits

Author SHA1 Message Date
snipe 846613c244 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-03-22 20:48:02 -07:00
snipe c4c137dc08 Bumped to 4.2.0 2018-03-22 20:47:09 -07:00
snipe 130bb19a11 Merge branch 'develop' 2018-03-22 20:31:04 -07:00
snipe d0f14d7a3c Fixed #5186 - email being sent to admin as well as user on checkout
This should be introduced as a setting, but not arbitrarily send
2018-03-22 20:30:45 -07:00
snipe 795c2cf540 Merge branch 'develop' 2018-03-22 20:27:40 -07:00
snipe bcd02ce718 Inelegantly fixed #5186 - placeholder notification being sent
This needs work
2018-03-22 20:27:14 -07:00
snipe 469efc923b Merge branch 'develop'
# Conflicts:
#	README.md
#	config/version.php
2018-03-22 20:08:55 -07:00
snipe dcd74f6922 Bumped version 2018-03-22 20:07:06 -07:00
snipe 4b7eaf6dae Updated translations 2018-03-22 20:01:45 -07:00
Brady Wetherington 085f909f35 Change duplicate header check to return 1-based header indices 2018-03-22 19:40:12 -07:00
snipe 4f394b683d Added test CSV with blank column headers 2018-03-22 19:35:43 -07:00
snipe 7096ebedbc Sample CSV with duplicated headers 2018-03-22 19:22:28 -07:00
Brady Wetherington 0b0243a5e0 Hoist file-reading before file-renaming, catch duplicate headers (#5244) 2018-03-22 19:16:15 -07:00
snipe 5c9f9b1685 Add @cepacs as a contributor 2018-03-22 15:49:46 -07:00
snipe bf74bb196d Merge branch 'develop' 2018-03-22 14:57:15 -07:00
snipe c6e14caa31 Removed e() from array_smart_custom_field_fetch 2018-03-22 14:36:36 -07:00
snipe 506602b257 Remove escaping on import value checker 2018-03-22 14:25:52 -07:00
snipe a79ec0d408 Merge branch 'develop' 2018-03-22 14:18:30 -07:00
snipe 140724be2e Fixed #5217 - permissions error with importer for non-admins 2018-03-22 14:17:44 -07:00
snipe 04af1f3c97 Moved remote user stuff below password security stuff 2018-03-22 14:00:35 -07:00
snipe cb4f1daac1 Fix for a bad merge - the migration was changed between master and develop :( 2018-03-22 13:45:55 -07:00
snipe 96bab5697d Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	config/version.php
#	database/migrations/2018_02_22_160436_add_remote_user_settings.php
2018-03-22 09:46:50 -07:00
snipe abac3e7758 Bumped hash 2018-03-22 09:44:54 -07:00
snipe 8557cb5305 Added - make accessory manufacturer field searchable 2018-03-22 09:43:53 -07:00
tiagom62 735840aafd Revert removing setting hostname (#5208) 2018-03-21 19:09:37 -07:00
David Kaatz 1c777888d5 Authentication via REMOTE_USER (clean repull) (#5204)
- Implementation in Login
- Configuration
- Database migration
2018-03-21 19:09:37 -07:00
Brady Wetherington 625810cd8a Support \r-terminated files better from the Importer (#5184)
* Hoist the ini_get/ini_set auto-detect line endings code higher

* Placate the irascible Codacy
2018-03-21 19:08:06 -07:00
Anh DAO-DUY cd63abd72e Add default_label field missing in status_labels table (Travis CI) (#5180) 2018-03-21 19:08:06 -07:00
snipe d911b776bf Check for associated maintenance asset
This should probably never happen, but triggers on the demo sometimes because of fluctuating data seeding
2018-03-21 19:08:06 -07:00
tiagom62 9e7d1b3ed8 Revert removing setting hostname (#5208) 2018-03-15 10:20:42 -07:00
David Kaatz 53735f2026 Authentication via REMOTE_USER (clean repull) (#5204)
- Implementation in Login
- Configuration
- Database migration
2018-03-14 12:48:07 -07:00
David Kaatz a43b31400f Authentication via REMOTE_USER (#5142)
* Added authentication via Remote User

* - Removed nullable from remote_user settings fileds and used just default values instead
- Removed german translations
- Removed 401 error page and replaced usage with 403 error page as 401 was actual a duplicate of 403
- Replaced usage of $_SERVER['REMOTE_USER'] with Laravels API Request::server('REMOVE_USER')

* - Fixed request usage
2018-03-13 20:07:52 -07:00
Brady Wetherington e15f2ac8ab Support \r-terminated files better from the Importer (#5184)
* Hoist the ini_get/ini_set auto-detect line endings code higher

* Placate the irascible Codacy
2018-03-13 20:06:53 -07:00
Anh DAO-DUY 06e760081c Add default_label field missing in status_labels table (Travis CI) (#5180) 2018-03-09 13:05:14 -08:00
snipe fc8637c81a Check for associated maintenance asset
This should probably never happen, but triggers on the demo sometimes because of fluctuating data seeding
2018-03-07 22:22:36 -08:00
snipe 01eaf48471 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-03-07 18:25:12 -08:00
snipe 238a075c6a Bumped hash 2018-03-07 18:24:09 -08:00
snipe 1d130b4a89 Fixed asset model permission not granted for edit 2018-03-07 18:22:49 -08:00
snipe 95d935d917 Added warning to not edit config files manually 2018-03-07 17:39:13 -08:00
snipe c4db8d37c2 Fixed #5168 - users without superadmin could not see custom fields UI even if granted 2018-03-07 13:37:37 -08:00
snipe 17e0154995 Fixed #5160 - make field_values readable via custom fields API 2018-03-06 13:11:45 -08:00
snipe d60c9800c2 Check that the id key exists to prevent any weird edge cases for location 2018-03-05 22:44:05 -08:00
snipe 04d2542b81 Fixed #5078 - check for object or array as location in LDAP sync 2018-03-05 22:42:40 -08:00
snipe 9a25cb3ee7 Set default labels in seeders 2018-03-05 22:16:36 -08:00
snipe 1e22b8e567 Fixed #5138 - added default_label flag to status labels 2018-03-05 22:04:16 -08:00
snipe d05dfb18a7 Fixed #5150 - added lastname first initial as username format 2018-03-05 21:39:05 -08:00
snipe a5c6ddb8ac Change gate for updating assets via the API to edit 2018-03-05 21:27:17 -08:00
snipe 90bff709a4 Merge branch 'develop' 2018-03-05 20:58:08 -08:00
snipe 052132ec37 Remove pyrchase cost from accessory search 2018-03-05 20:57:50 -08:00
snipe d42361bac1 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-03-05 20:27:50 -08:00
snipe 2df19bcbb4 Only pull category matches for accessory category 2018-03-05 20:22:44 -08:00
snipe 0ef4251462 Include new icons in stalebot 2018-03-05 19:06:39 -08:00
snipe a4af81563a Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2018-03-05 16:26:49 -08:00
snipe 36cd63836e Fixed #5151 - added asset tag to maintenances 2018-03-05 16:26:40 -08:00
tiagom62 48f9959fcd snipeit.sh improvements (#4708)
* snipeit.sh improvements

* Missing dependency for upgrade.php #4726

* Upgrade noninteractively
2018-03-04 21:48:44 -08:00
snipe 9effa3d2ab Fixed manufacturer restore 2018-03-03 19:14:27 -08:00
snipe 0782222c6b Removed commenting
This restore() is still not working, though not sure why. Seems like it should be pretty straghtforward, and yet…

Additonally, manually setting the deleted)at date to null or blank isn’t working either. I’m sure I’m just missing something obvious.
2018-03-03 18:49:02 -08:00
snipe f7784b6543 Fixed #2402 - add ability to restore manufacturers 2018-03-03 18:46:19 -08:00
snipe fabc9e5d1c Bumped hash 2018-03-03 17:15:59 -08:00
snipe 06805d70fe Fixed incorrect settings HTML 2018-03-03 17:07:28 -08:00
snipe 123e317e52 Check for an array (for PHP7.2 support) 2018-03-03 17:07:07 -08:00
fordster78 68a9855506 New First Admin Notification (#5147)
* New First Admin Notification

* Include Last name in Welcome and First admin Notifications
2018-03-03 14:37:42 -08:00
fordster78 688a3251a9 New Welcome Notification (#5146)
* New Test Notification

Created Test Notification.
Updated Vendor Mail message.blade files.
Updated api settings controller to use Notification Façade.

* Add show URL in Emails condition

* New Welcome Notification
2018-03-03 12:44:41 -08:00
snipe 30c5cc1dc4 Additional dark themes 2018-03-02 20:01:41 -08:00
snipe 4ab1d5ca7f Fixed #5110 - crash on accessory checkin missing last_name 2018-03-02 19:26:41 -08:00
snipe 5a808a0f91 Fix for header color in green skin 2018-03-02 19:17:12 -08:00
snipe a6cc31944a Added package-lock 2018-03-02 19:17:01 -08:00
snipe 41a9e5f710 Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2018-03-02 18:01:41 -08:00
snipe 31790e0bb7 Tweaks to theme settings 2018-03-02 18:01:36 -08:00
fordster78 4e0c8e218d New Test Notification (#5137)
Created Test Notification.
Updated Vendor Mail message.blade files.
Updated api settings controller to use Notification Façade.
2018-03-02 18:01:20 -08:00
Geoff Young 4fe4c0c72a Add viewKeys permission check on Asset page (#5141) 2018-03-02 18:00:22 -08:00
snipe f171357e36 Removed unused skin files, added skin setting option 2018-03-02 17:50:40 -08:00
snipe ef91cc992e Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2018-03-02 16:52:00 -08:00
snipe 04b92f2ad2 Added info on third-party libraries 2018-03-02 16:51:56 -08:00
Tim F 4f049112de Patch for dark-green.css to include more in template. (#5122)
* Update dark-green.css

Added several new rules, to include little bits that weren't previously. Mostly centered around the new 'form' page and the various settings pages.

* Update dark-green.css

Fixed buttons for "View All" on main page. Missed those previously. Well, the buttons were included, but not the hover effects.
2018-03-01 20:45:22 -08:00
Tim F 86242b322c Create dark-green.css (#5118) 2018-02-27 14:10:08 -08:00
Tim F 14af95001e Create dark-green.css (#5117) 2018-02-27 13:37:12 -08:00
snipe 2dd56f5bda Backup the .env if BACKUP_ENV is set to true 2018-02-26 18:12:48 -08:00
snipe c250c632f3 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-26 15:46:49 -08:00
snipe e3fb4f8799 Bumped hash 2018-02-26 15:44:36 -08:00
snipe b4f704d7f1 Fixed 2FA reset button 2018-02-26 15:43:49 -08:00
Daniel Meltzer 9ee2c6be57 Api tests2 (#5098)
* Cleanup

* API tests for asset models and related cleanup/improvements

* Api license test.  Tests incomplete because create/update/destroy are not implemented yet in the controller

* API Category tests.

* Manufacturers API Test.

* Implement License Create/Update/Delete Methods for API and enable test.

* Add missing gate for api.  Fixes only superadmins being able to generate Personal Access Toekns
2018-02-25 12:10:02 -08:00
Daniel Meltzer 7de8f71f58 Api tests (#5096)
* Use the formated date helper to clean up verifications.

* Add Checkin/Checkout api tests.

* Accessories api test

* Add Companies API Test.

* Return ModelNotFound as a 404.

* Cleanups/simplficiations/updates.

* Locations api test.

* currency and image should be fillable on location.

* Update components api test.

* Use findOrFail so we return a 404 instead of a 200.  Matches other item types.

* order_number should be fillable in component.

* Add updated_at and permissions to information returned from api for a user.

* Add users test and flesh out factory and fillable fields.

* Add test for assets method

* API status label test.

* Disable php7.2 for now on travis until the count(null) issues are remedied

* Add serial to update.

* API model not found should return a 200
2018-02-24 19:01:34 -08:00
snipe b6a75093b7 Removed duplicate location_id assignment 2018-02-24 14:06:10 -08:00
Daniel Meltzer d54dda40d3 Functional Tests Improvements (#5095)
* Rely on laravel transactions instead of refreshing the database dump between functional test runs.  Cuts functional test runtime by 75%.  Also use mysql to seed directly.

* Split functional tests into two groups on travis to reduce overall memory usage.  Any new tests will need to be added to one of these two files before they are run on travis.  running all functional tests simultaneously still works locally.

* Fix name of test in group.
2018-02-24 12:03:33 -08:00
snipe a705c714ab Merge branch 'develop' 2018-02-23 05:53:44 -08:00
snipe 0e48837eec Fixed assets checked out to assets listing table 2018-02-23 05:53:00 -08:00
snipe 5e5ba54c3e Disallow checkout asset to itself 2018-02-23 05:52:19 -08:00
snipe 4403b139d5 Merge branch 'develop' 2018-02-23 05:12:49 -08:00
snipe 103974cae4 Fixed statuslabel detail view table 2018-02-23 05:09:14 -08:00
snipe aea37467d8 Attempt to add codeclimate test coverage 2018-02-22 22:34:08 -08:00
snipe 9d2ed7bc5f Merge branch 'develop' 2018-02-22 21:49:37 -08:00
snipe bfb11d249e Tweaked slack test UI 2018-02-22 21:47:48 -08:00
Daniel Meltzer f7dbda4ed3 Disable broken tests (#5073)
* Work towards a functional travis.  Step 1: Disable broken unit tests.

* Fix functional tests

This updates the login information and model factories to work with
changes to source.

* Importer name/full name fixes.

Fix a bug where "name" was used ambigously and mapping "item name" to
"name" would confuse the importer into thinking it should also be a user
name.  Now we default to "full name" for the users name, and "item name"
for the item name.  These are still both configurable through the custom
mapping.

Also update sample csvs and remove an outdated sample.

* Max length of supplier notes is 191, not 255, as per default laravel string length.  Might make sense to change this to a text field in the future to match other places.

* Use sqlite/different db setup for unit tests.

* Fix assets api test.

* Fix Components API test.

* increase travis memory limit for functional tests.

* Use travis config for api tests as well.

* Fix memory limit file.

* Disable ApiComponentsAssetsCest until it's fixed.
2018-02-22 21:46:58 -08:00
snipe 7c9c6ea3df Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-22 16:40:19 -08:00
snipe 7d49c4de87 Bumped hash 2018-02-22 16:39:12 -08:00
snipe e49a36c9fd Fixed #5084 - min supplier name now 1 2018-02-22 16:37:05 -08:00
snipe 236e773438 Fixed incorrect component not found string 2018-02-22 16:36:01 -08:00
snipe e3144c3093 Added Slack test button 2018-02-22 16:35:34 -08:00
snipe cbd8409611 Fixed #5067 - account for only one name in generateFormattedNameFromFullName 2018-02-22 14:10:58 -08:00
snipe a85b38850c Added roave security-advisories to composer
https://packagist.org/packages/roave/security-advisories
2018-02-22 13:22:13 -08:00
snipe e01f1ae8ed Partial fix for #2892 - Added export for license seat assignments 2018-02-21 17:28:55 -08:00
snipe d60a4c5f87 Merge branch 'develop' 2018-02-21 16:47:03 -08:00
snipe 9c1fe2c922 Reverting previous change - qty already existed in allowed columns. Derp. 2018-02-21 16:46:37 -08:00
snipe 3131c0d0ac Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 16:45:21 -08:00
snipe 364e9cf3de Bumped version 2018-02-21 16:43:00 -08:00
Daniel Meltzer 5a84863873 Importer name/full name fixes. (#5072)
Fix a bug where "name" was used ambigously and mapping "item name" to
"name" would confuse the importer into thinking it should also be a user
name.  Now we default to "full name" for the users name, and "item name"
for the item name.  These are still both configurable through the custom
mapping.

Also update sample csvs and remove an outdated sample.
2018-02-21 16:42:36 -08:00
snipe 006b2b18b0 Added qty to sorting 2018-02-21 16:21:31 -08:00
snipe fb262e38a7 Added - make total sortable in components 2018-02-21 16:21:21 -08:00
snipe f8151284ee Fixed - removed extra components table 2018-02-21 16:20:46 -08:00
snipe 5d8c91b687 Fixed regression - Added sum footer back into accessories 2018-02-21 15:54:16 -08:00
snipe 0f23462607 Merge branch 'develop' 2018-02-21 15:51:33 -08:00
snipe ca50ea190f Applied master changes to develop
Wrong branch :(
2018-02-21 15:51:04 -08:00
snipe 31192abd2c Fixed ambniguous query in asset maintenance search 2018-02-21 10:28:05 -08:00
snipe 42c7f41d24 Added some alerting in custom fields if it looks like the db_column and real column do not match 2018-02-21 10:06:23 -08:00
snipe fade03e337 Added nicer gates for auditing 2018-02-21 08:13:18 -08:00
snipe d511d90a2f Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 06:50:42 -08:00
snipe 54d6cafda9 Bumped hash 2018-02-21 06:49:36 -08:00
snipe a730cd1c51 Fixed - better handle admin routes when user is not logged in
Redirect to login instead of just showing forbidden
2018-02-21 05:51:49 -08:00
snipe cccd75fc42 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 05:48:02 -08:00
snipe dbc16a6c9b Bumped hash 2018-02-21 05:47:12 -08:00
snipe 6ffad6043f Fixed issue where bootstrap tables didn’t use a default page size 2018-02-21 05:44:41 -08:00
snipe 4e398950a0 Merge branch 'develop' 2018-02-21 05:34:02 -08:00
snipe f5e51897e3 Added - sort by color on status labels 2018-02-21 05:29:50 -08:00
snipe 698ea36cc2 Added - Order location by manager 2018-02-21 05:09:40 -08:00
snipe 0cf9cdd3b1 Make department columns sortable 2018-02-21 05:04:20 -08:00
snipe 42c8de5620 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 04:44:48 -08:00
snipe ba4f63bca3 Bumped version 2018-02-21 04:43:52 -08:00
snipe 4ed2ef6298 Merge branch 'develop' 2018-02-21 04:42:03 -08:00
snipe d28c2af7de Fixed bootstrap table issue if per page was set to 10 2018-02-21 04:41:44 -08:00
snipe 1e8c32fbdb Fixed - missing table prefix for location parent search 2018-02-21 04:33:47 -08:00
snipe 97bd87773c Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 02:40:23 -08:00
snipe b560828173 Bumped hash 2018-02-21 02:18:14 -08:00
snipe 0d7a43ab38 Fixed orderby parent location name 2018-02-21 02:17:18 -08:00
snipe 7865fbea7e Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-21 01:27:11 -08:00
snipe 5fcbf9091e Bumped version 2018-02-21 01:23:19 -08:00
snipe fedd2b638c Merge branch 'develop' 2018-02-21 01:20:48 -08:00
snipe 22f44e342f Fixed incorrect next audit date if asset override 2018-02-21 01:18:21 -08:00
snipe f7eb013935 Reverse order on activity report 2018-02-20 15:42:44 -08:00
snipe 1c28f893e7 Fixed #5027 - remove link to non-existant reports page 2018-02-20 14:44:29 -08:00
snipe 195dfd752d Updated translations 2018-02-20 14:41:12 -08:00
snipe cc788d3b62 Added Slovenian 2018-02-20 14:37:22 -08:00
snipe e54021e7be Added Venzuelan spanish 2018-02-20 14:37:12 -08:00
snipe 918db39eba Merge branch 'develop' 2018-02-19 18:06:58 -08:00
snipe 213fe2ecea Fixed #5044 - incorrect env values for SSL DB paths 2018-02-19 18:03:50 -08:00
snipe 6e70352d0b Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-17 01:05:20 -08:00
snipe d2403cdadb Added image preview for uploads 2018-02-17 00:51:22 -08:00
snipe 9a4f5e0ba8 Bumped hash 2018-02-16 22:10:06 -08:00
snipe 502e4d672a Use image upload partial in asset edit/create 2018-02-16 22:08:49 -08:00
snipe 99205bf72e Merge branch 'develop' 2018-02-16 21:39:15 -08:00
snipe b3d673b0aa Fixed #5037 - use line breaks in notes in table view 2018-02-16 21:38:56 -08:00
snipe baf51eb430 Merge branch 'develop' 2018-02-16 21:19:03 -08:00
snipe d8fc50c351 Fixed #5033 - use PHP’s max filesize for image uploads 2018-02-16 21:17:41 -08:00
snipe ba5057181e Check for model in asset view 2018-02-16 18:04:11 -08:00
snipe 4c4dee0bf1 Use dropifexists for rollback 2018-02-16 17:45:40 -08:00
snipe 589c3a2be3 Fixed #4668 - wrong gate on manufacturer save 2018-02-16 17:45:27 -08:00
snipe 991f182f89 Added drop table to migration 2018-02-16 15:36:33 -08:00
snipe f44b03f5a9 Updated sticky table header extenion 2018-02-16 15:36:21 -08:00
snipe 5fd50040d3 Fixed weird migration 2018-02-16 15:31:47 -08:00
snipe 5302108556 Update to master 2018-02-16 13:27:03 -08:00
snipe 592c62de75 Merge branch 'develop'
# Conflicts:
#	README.md
#	config/version.php
2018-02-16 13:26:53 -08:00
snipe 27c1bc0271 Bumped hash 2018-02-16 13:24:47 -08:00
snipe 3744a68daf Features/better table options (#5018)
* Added CSS for table toolbar

* Use maintenances API for table listings

* NIcer layout for allowed_columns in maintenances API

* Fixed #5014 - bootstrap cookie issues

* Fixed #5015 - bug when saving settings

* Refactored datatable code to use data attributes

* Updated dashboard with new table code

* Added - Order by group user count

* Updated groups to use new table attributes

* New license listing table code

* More bootstrap table implementations

* More BS table refactoring

* Improved bootstrap assigned assets

* New bootstrap for reports

* Misc BS fixes

* FIxed small issue with asset history display

* Removed multisort option

* JS refactor
2018-02-16 13:22:55 -08:00
dl1l c209b7bb5d Update edit.blade.php (#5019) 2018-02-15 14:59:54 -08:00
snipe f04493c1ab Added firstname_lastname as possible username format 2018-02-13 20:31:51 -08:00
snipe 62edf14893 Refactored method to generate usernames from full names 2018-02-13 20:31:11 -08:00
snipe 0d11e32523 Fixed issue where group with no permissions would crash view page 2018-02-13 17:14:30 -08:00
snipe 5484b06df8 Fixed #4923 - invalid check for location object in Ldap Sync 2018-02-13 17:06:42 -08:00
snipe 9f3116e4e3 Added - Deep linking in Bootstrap tabs 2018-02-13 17:04:50 -08:00
snipe f144d671ff Fixed #4988 - incorrect variable name in asset checkout API method 2018-02-12 19:13:33 -08:00
snipe b294635e17 Updated packages 2018-02-08 09:29:12 -08:00
snipe 36234cc0e8 Add @seanmcilvenna as a contributor 2018-02-08 09:29:12 -08:00
snipe 5c87003196 Added code triage badge 2018-02-08 09:29:12 -08:00
Sean McIlvenna cc5d36f8be Addng "Category" column to "view assets" and re-organizing columns (#4970) 2018-02-05 17:36:35 -06:00
README Bot 1359a4f88a Add CodeTriage badge to snipe/snipe-it (#4968)
Adds a badge showing the number of people helping this repo on CodeTriage.

[![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it)

## What is CodeTriage?

CodeTriage is an Open Source app that is designed to make contributing to Open Source projects easier. It works by sending subscribers a few open issues in their inbox. If subscribers get busy, there is an algorithm that backs off issue load so they do not get overwhelmed

[Read more about the CodeTriage project](https://www.codetriage.com/what).

## Why am I getting this PR?

Your project was picked by the human, @schneems. They selected it from the projects submitted to https://www.codetriage.com and hand edited the PR. How did your project get added to [CodeTriage](https://www.codetriage.com/what)? Roughly 4 months ago, [@imjennyli](https://github.com/imjennyli) added this project to CodeTriage in order to start contributing. Since then, 8 people have subscribed to help this repo.

## What does adding a badge accomplish?

Adding a badge invites people to help contribute to your project. It also lets developers know that others are invested in the longterm success and maintainability of the project.

You can see an example of a CodeTriage badge on these popular OSS READMEs:

- [![](https://www.codetriage.com/rails/rails/badges/users.svg)](https://www.codetriage.com/rails/rails) https://github.com/rails/rails
- [![](https://www.codetriage.com/crystal-lang/crystal/badges/users.svg)](https://www.codetriage.com/crystal-lang/crystal) https://github.com/crystal-lang/crystal

## Have a question or comment?

While I am a bot, this PR was manually reviewed and monitored by a human - @schneems. My job is writing commit messages and handling PR logistics.

If you have any questions, you can reply back to this PR and they will be answered by @schneems. If you do not want a badge right now, no worries, close the PR, you will not hear from me again.

Thanks for making your project Open Source! Any feedback is greatly appreciated.
2018-02-05 15:22:52 -06:00
snipe 1e1362bdbc Merge branch 'develop' 2018-02-02 09:42:50 -06:00
snipe 813106efd3 Default to only changing default location in bulk edit 2018-02-02 09:42:34 -06:00
snipe 08d129c2ea Fixed #4951 - updating asset location in bulk edit 2018-02-02 09:36:40 -06:00
snipe 8491e57258 Merge branch 'develop' 2018-02-02 09:32:00 -06:00
snipe d86fb098a8 Fixed sort ordering on dashboard 2018-02-02 09:31:43 -06:00
snipe e21f8e46d4 Merge branch 'develop' 2018-02-01 17:18:16 -06:00
snipe b3a6ec2804 Fixed #4938 - default sort order 2018-02-01 17:17:56 -06:00
snipe 0034938c04 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-02-01 16:32:13 -06:00
snipe d2587337e4 Fixed #4952 - ignore show_archived setting when drilling down into specific ID 2018-02-01 16:31:32 -06:00
snipe 8b2045523d Bumped hash 2018-02-01 15:55:33 -06:00
snipe e7e10c24be Add departments to usr export 2018-02-01 15:54:49 -06:00
snipe f06852f48d Merge branch 'develop' 2018-01-25 13:17:11 -06:00
snipe 2f9fff7130 Do not try to show depreciation report if no depreciations are set up 2018-01-25 13:16:49 -06:00
snipe 0b788f64f7 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-25 11:07:18 -08:00
snipe facf1d42f7 Sigh. 2018-01-25 11:06:37 -08:00
snipe e77aae703b Bumped hash 2018-01-25 11:03:45 -08:00
snipe 76f52dd89b Fixed #4872 - Check for assigned in depreciation table 2018-01-25 11:02:46 -08:00
snipe 0e980f7229 Hotfix: Disabling the event dispatcher broke model validation. (#4912) (#4915)
* Hotfix: Disabling the event dispatcher broke model validation.

This resulted in invalid data being imported.  Reenable the event dispatcher for now--this causes double logs, but at least validates properly.

* Actually disable the event dispatcher.

* Sign in where necessary to fix the importer unit test.  This catches the issues found manually in 4912
2018-01-25 10:29:06 -08:00
Daniel Meltzer 2f5d550df6 Hotfix: Disabling the event dispatcher broke model validation. (#4912)
* Hotfix: Disabling the event dispatcher broke model validation.

This resulted in invalid data being imported.  Reenable the event dispatcher for now--this causes double logs, but at least validates properly.

* Actually disable the event dispatcher.

* Sign in where necessary to fix the importer unit test.  This catches the issues found manually in 4912
2018-01-25 10:10:56 -08:00
snipe 3acf5f76fe Merge branch 'develop' 2018-01-25 03:35:30 -08:00
snipe 4be8ae7f3d Fuckery. 2018-01-25 03:34:52 -08:00
snipe 029dd43ecd Merge branch 'develop' 2018-01-25 03:01:35 -08:00
snipe cf8feb37e1 Fixed crash if no model associated
This should never be triggered. Bad data is getting in somehow.
2018-01-25 03:00:54 -08:00
snipe 648531f4cc Merge branch 'develop' 2018-01-25 00:26:17 -08:00
snipe 11505d5d06 Fix crash if no asset model
(This should never happen, but shouldn’t crash if/when it does)
2018-01-25 00:25:43 -08:00
snipe 1d04897b32 Order by default location 2018-01-24 14:27:12 -08:00
snipe eddcc0fbbd Fixed cookie issue on hardware 2018-01-24 14:23:19 -08:00
snipe bd80a77b78 Added default location to asset listing 2018-01-24 14:23:12 -08:00
snipe edc30a31c1 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-24 11:02:46 -08:00
snipe f5636f325d Bumped hash 2018-01-24 11:01:51 -08:00
snipe 426bf3803b Merge branch 'develop' 2018-01-24 11:00:40 -08:00
snipe 739d3c72b7 Fixed #4902 - include last name in checkin email 2018-01-24 10:59:34 -08:00
snipe 60c38a0c47 Added setting to choose what appears in model select list - Fixes #4879 2018-01-24 10:43:46 -08:00
snipe 9566fbd3cd Fixed borked down() migrations 2018-01-24 10:41:49 -08:00
Anh DAO-DUY e41ee1bcf8 Fix upload images problem with Docker (#4906)
Some folders were missing in this script file (Docker installation).
Missing folders caused errors while uploading some images.
2018-01-24 09:13:03 -08:00
Tim Bishop bc14f225af Only use location currency if it's actually set. (#4904)
This changes the depreciation report to only use the currency on a
location if it's actually set to something. Previously, if an asset had
a location it would use the currency even if it was blank rather than
falling back to the default.
2018-01-24 08:55:51 -08:00
snipe 07148c1503 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-24 08:29:25 -08:00
snipe fcb5eea951 Bumped hash 2018-01-24 08:28:53 -08:00
snipe 7a4bf26733 Merge branch 'develop' 2018-01-24 08:25:36 -08:00
snipe 2c2910d1dd Handle shitty edge cases where an asset has no model without crashing 2018-01-24 08:16:05 -08:00
snipe 1dae7a2fe4 Fixed #3636 - removed thread_id (we don’t use this anymore) 2018-01-24 08:00:28 -08:00
snipe e19ab329bd Add @tdb as a contributor 2018-01-24 07:13:24 -08:00
snipe 922cb90cb3 Add @CronKz as a contributor 2018-01-24 07:12:59 -08:00
snipe 765295136a Added - ability to add custom footer text, hide user’s manual/support links 2018-01-24 07:02:30 -08:00
snipe 7579333ad3 Disallow LDAP settings if in demo mode 2018-01-24 05:50:31 -08:00
snipe 543ea28b72 Added qty to asset components - fixed #4876 2018-01-24 05:25:01 -08:00
snipe fefd6d60f6 Fixed #4899 - sorting in user history 2018-01-24 04:48:00 -08:00
snipe a7b8b4bf55 Added: ability to change actual location from bulk edit assets 2018-01-24 04:38:25 -08:00
snipe 7cafa194c1 Fix for counts 2018-01-24 04:26:15 -08:00
snipe b37f78dbbf Fixed #4858 - wrong params for id count 2018-01-24 04:24:45 -08:00
snipe e20cd42cc2 More parse error fixes 2018-01-24 03:42:49 -08:00
snipe 7b99f81f72 Fixed parse error on hardware blade 2018-01-24 03:38:29 -08:00
snipe f1bbdc9e59 Revert PR #4845 2018-01-24 03:32:45 -08:00
Richard Hofman 5219fb63a1 Add --base_dn option to LdapSync command. (#4888) 2018-01-23 18:15:36 -08:00
CronKz dcc379c3fa Adding missing translations. (#4896) 2018-01-23 18:13:55 -08:00
vcordes79 0fb8dc3418 check if user is allowed to view assets (#4845) 2018-01-23 18:10:05 -08:00
vcordes79 f4e9d245d0 Status labels (#4895)
* fix statuslabels

* fix statuslabels
2018-01-23 18:08:54 -08:00
snipe c75a2051ff Hide mfg button if no permissions to create 2018-01-22 14:02:23 -08:00
CronKz 691ec164b1 Added Translations (#4880) 2018-01-22 13:14:52 -08:00
vcordes79 7b596c750d API for (dis)associating fields with fieldsets (#4881)
* start work on fields in fieldset api

* revert CustomFieldsetsController

* fieldset associate / disassociate api

* fix variable names and payload

* fix variable name
2018-01-22 13:14:04 -08:00
Tim Bishop b346556caa Allow manager_id to be fillable. (#4882)
The API UsersController accepts manager_id, but calls the following:

$user->fill($request->all());

This results in manager_id being ignored. I can't see any problem with
allowing a user's manager to be modified using the API, so this change
allows it.
2018-01-22 13:12:02 -08:00
snipe 93ec7068df Removed a few additional unused badges 2018-01-20 08:54:49 -08:00
snipe 5f65f993a0 Small refactor for AssetPresenter method 2018-01-20 08:52:50 -08:00
snipe a9441521a4 Small refactor for Setting method 2018-01-20 08:52:50 -08:00
snipe 2dede67ae9 Removed unusued badges 2018-01-20 08:52:49 -08:00
Daniel Meltzer 6bf17e7d47 Reset the item between rows of import to avoid stale data. (#4868) 2018-01-20 08:40:01 -08:00
snipe a3240da707 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-20 07:47:54 -08:00
snipe a28fee1ff4 Bumped hash 2018-01-20 07:47:07 -08:00
snipe 57e5af2f69 Removed console logging from JS 2018-01-20 07:42:48 -08:00
snipe 8d3a214475 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-20 04:56:36 -08:00
snipe 58eedce6fe Updated language files 2018-01-20 04:53:04 -08:00
snipe f91704a372 Added Ukrianian to language dropdown 2018-01-20 04:49:40 -08:00
snipe f53c68e040 Bumped hash 2018-01-20 04:40:26 -08:00
snipe 99e55f84f0 Fixed misc UI permissions elements 2018-01-20 04:39:31 -08:00
snipe 798ea75f3d Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-20 04:00:26 -08:00
snipe 913e6a5709 Bumped hash 2018-01-20 03:59:42 -08:00
snipe 34f6d5ab45 Fixed #4671 - corrected component checkin gate 2018-01-20 03:58:59 -08:00
snipe 86c0194e9a Fixed #4628 and #4590 - Illegal mix of collations for operation error when searching on some languages 2018-01-20 03:08:27 -08:00
Brady Wetherington dfb2b9b569 Major overhaul for modals, and a fix for #4820 (#4866)
Changes how the various modals work, and allows for specifying
category_type when inline-creating categories.
2018-01-20 00:42:29 -08:00
snipe 7fae380ab6 Fixed #4300 - Fix for illegal character type in action log 2018-01-20 00:27:45 -08:00
snipe 4ca8272efc Merge branch 'develop' 2018-01-20 00:21:03 -08:00
snipe 5d4bbc393e Fixed #4837 - link phone numbers 2018-01-20 00:20:45 -08:00
snipe 984275ff05 Merge branch 'develop' 2018-01-19 23:47:54 -08:00
snipe e6f70f2ab7 Fixed #4821 - add username to user selection dropdown 2018-01-19 23:47:37 -08:00
snipe f7de252f67 Wrong branch. :( 2018-01-19 23:46:42 -08:00
snipe 532b299c40 Fixed #4821 - add username to user selection dropdown 2018-01-19 23:46:12 -08:00
snipe 5dcc63dc74 Merge branch 'develop' 2018-01-19 20:49:20 -08:00
snipe 6eb8acf319 Swich to panel box for dashboard message 2018-01-19 20:49:02 -08:00
snipe 862251ab36 Change label to stale 2018-01-19 20:45:25 -08:00
snipe 95a9742571 Fixed #4768 - adds dashboard message option to settings 2018-01-19 20:43:55 -08:00
snipe 81d0921782 Merge branch 'develop' 2018-01-19 19:18:43 -08:00
snipe 0fa556da1d Exempt ready for dev and bounty tags from stale collection 2018-01-19 19:16:35 -08:00
snipe 05bc238c9a Merge branch 'develop' 2018-01-19 18:17:38 -08:00
snipe 782813ab49 Check for valid category before checking acceptance 2018-01-19 18:17:23 -08:00
snipe cbca126d9d Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-19 17:53:15 -08:00
snipe a9ffe8d210 Bumped hash 2018-01-19 17:52:40 -08:00
snipe c242abb42e Added Company policy to fix company deletion issue 2018-01-19 17:51:28 -08:00
snipe 2c722ffc4f Fixed issue template with correct path to storage logs 2018-01-19 16:31:01 -08:00
snipe 484c47cef8 Added stale.yml to auto-close stale issues 2018-01-19 16:23:28 -08:00
snipe f38dc37152 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-17 19:31:09 -08:00
snipe 6133f09056 Bumped hash 2018-01-17 19:30:31 -08:00
snipe 2a959edeba Added - Setting to allow archived assets in List All 2018-01-17 19:18:48 -08:00
snipe 8995d689b8 Fixed #4817 - [BREAKING API CHANGE] - changed user API response from firstname, lastname to first_name, last_name 2018-01-17 13:25:11 -08:00
snipe f08bec6c78 Merge branch 'develop' 2018-01-17 13:12:58 -08:00
snipe d920d91786 Fixed #4593 - do not require model_id to update asset custom fields via API 2018-01-17 13:12:32 -08:00
snipe e35b3745eb Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-17 12:41:51 -08:00
snipe e8252d9468 Bumped hash 2018-01-17 12:41:11 -08:00
snipe 8fff6a1a06 Update asset location based on user checkout in bulk checkout 2018-01-17 12:39:49 -08:00
snipe 0eff821928 Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-17 12:12:33 -08:00
snipe 9e605e0f79 Bumped hash 2018-01-17 12:11:39 -08:00
snipe 8fb991110e Fixed #4652 - asset not correctly checking out to user on creation 2018-01-17 12:10:28 -08:00
snipe b383ebee48 Add @fordster78 as a contributor 2018-01-17 10:59:00 -08:00
fordster78 138313dcb9 Setup changes (#4813)
* Add Asset Tag settings to Setup

* Add Locale Settings to Setup

* Add multiple company support to setup

* Changed the locale label name from 'site_name' to locale
Added default value for language to 'en' and multiple companies support
to 0 (false)
Switched out the old Input facade to the preferred $request->input
method for the setup page.
2018-01-17 10:58:03 -08:00
snipe f254958db9 Check if db_column foield already exists 2018-01-17 06:48:14 -08:00
snipe 09eff88679 Merge branch 'develop' 2018-01-17 06:28:11 -08:00
snipe 24b356dba4 Fixed typos in default blade that cause components to not show up for non-superadmins 2018-01-17 06:27:23 -08:00
snipe 91bca5fcba Fixed #4844 - use input value for ids in user bulk edit 2018-01-17 06:15:52 -08:00
vcordes79 96a469db36 allow changing user activated field via api (#4843) 2018-01-17 05:38:10 -08:00
snipe 9ab05e7037 Add @vcordes79 as a contributor 2018-01-17 05:36:15 -08:00
vcordes79 52a99faf68 fix phone number update in api (#4842) 2018-01-17 05:33:55 -08:00
vcordes79 94cf1f8741 Fixes #4829 - add fields api (#4840)
* add fields api

* change route names
2018-01-17 05:31:57 -08:00
snipe e2a8f9b790 Merge branch 'develop' 2018-01-17 03:27:03 -08:00
snipe 409f5cc4fd Added - display asset model category on hardware view page 2018-01-16 16:26:24 -08:00
snipe 3b5e4c44eb Fixed depreciation report not showing assigned to 2018-01-16 07:46:34 -08:00
snipe 69a7ea63e2 Pass nopages to dashboard stuff 2018-01-16 07:37:20 -08:00
snipe aac379daeb If nopages is passed, hide page numbers
This seems weird since we’re checking for a negative, but there are only a few spots where we wouldn’t want page numbers, namely the dashboard sruff
2018-01-16 07:37:06 -08:00
snipe 1d3472b5c4 Truncate the checkout_requests field on seed 2018-01-16 07:36:14 -08:00
snipe 66a590b774 Account for user’s that have been deleted in the requested list 2018-01-16 07:36:03 -08:00
snipe dc4472e9e9 Misc export table fixes 2018-01-15 21:03:46 -08:00
snipe 6bfd428c2e Use real status label names, even if deployed 2018-01-15 21:03:26 -08:00
snipe f4623bd277 Add user group membership to user view page 2018-01-15 20:31:10 -08:00
snipe 1f04d7aafd Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-11 15:27:17 -08:00
snipe 78efeec368 Bumped hash 2018-01-11 15:24:37 -08:00
snipe 5b15a2fc0a Merge branch 'develop' 2018-01-11 15:23:27 -08:00
snipe 68f1fa0340 Added - ability to sort by asset count in models 2018-01-11 15:21:51 -08:00
snipe 9293f17707 Moved search scope lower to fix weird (possible Laravel) bug w/prepared statements 2018-01-11 15:17:34 -08:00
snipe a4b32e2328 Improved - use presenters on model detail 2018-01-11 15:17:10 -08:00
snipe d109ca30e2 Improved - allow searching on most detail views with additional tables 2018-01-11 15:16:53 -08:00
snipe 3b4a651dd9 Allow counts in mfg sorting 2018-01-11 15:16:23 -08:00
snipe a4ac53e2e9 Improved - Using presenters for column headers in location detail 2018-01-11 15:16:09 -08:00
snipe cf1b5a7685 Added- sort by count in manufacturer listing 2018-01-11 15:13:32 -08:00
snipe 0789eb8b07 Improved - using presenters for column headers in manufacturer detail 2018-01-11 15:12:48 -08:00
snipe 7f674fdd35 Require implicit search 2018-01-11 13:18:06 -08:00
snipe 500aa37e3c Fixed switchable attributes on table headers 2018-01-11 13:17:55 -08:00
snipe efe668d26d Merge branch 'develop'
# Conflicts:
#	config/version.php
2018-01-10 22:59:02 -08:00
snipe 90db97b980 Merge branch 'features/fixes_4792_ajax_tables_on_license_view' into develop 2018-01-10 22:57:44 -08:00
snipe bc3d27fac6 Bumped hash 2018-01-10 22:57:22 -08:00
snipe 55b9f1207d Updated bootstrap tables 2018-01-10 22:53:54 -08:00
snipe 2bbb6001a8 Added location to seats transformer 2018-01-10 20:36:27 -08:00
snipe af7b7664c5 Added license seat location method 2018-01-10 20:34:44 -08:00
snipe c31362655c Refactored BS tables include for clearer separation of simple v not simple 2018-01-10 20:34:36 -08:00
snipe c6a956382f Fixed #4784 - cookie not always being set correctly for ajax tables 2018-01-10 20:04:41 -08:00
snipe bab0bda174 Added custom formatter for license seats (WIP) 2018-01-10 18:58:55 -08:00
snipe bb52a8417c Switch view code to AJAX table 2018-01-10 18:58:41 -08:00
snipe e3d7be23cb Added new seats controller method 2018-01-10 18:47:57 -08:00
snipe 3d5545494e Added new seats transformer 2018-01-10 18:47:40 -08:00
snipe 7f1a535b30 Added new seats API route 2018-01-10 18:47:27 -08:00
snipe 254234b0dc Fixed #4787 - don’t try to display category if it is invalid
This shouldn’t be needed, but in case data got weird (manual editing, etc)
2018-01-10 06:33:59 -08:00
snipe 3566f37981 Merge branch 'develop' 2018-01-10 06:25:06 -08:00
snipe e6259eb6e1 Fixed #4774 - show assets assigned to assets in asset view
Todo: Fix text search on the asset to asset tab. It’s currently broken so I’ve disabled it.
2018-01-10 05:44:11 -08:00
snipe eeb3d1eb42 Use language strings for tab text 2018-01-10 05:42:34 -08:00
snipe 79295f6434 Use dataTableLayout for table 2018-01-10 05:33:45 -08:00
snipe 285e4e2e52 Allow bulk language update in user edit 2018-01-10 05:33:26 -08:00
snipe 5587b64d64 Fixed #4770 - broken licenses, etc on company view, added users and components 2018-01-10 03:52:21 -08:00
snipe f0f2a5aa67 Workaround for #4784 - make changes tab always visible
Not sure why the cookie isn’t cookie-ing
2018-01-10 01:56:24 -08:00
Brady Wetherington 061317866b Changes to Models in the asset-edit screen maintain chosen values (#4781)
Fixed for #2195
2018-01-09 23:45:20 -08:00
snipe 65ffc01583 Merge branch 'develop' 2018-01-09 20:19:50 -08:00
snipe f5f7a63a23 Production assets 2018-01-09 20:19:04 -08:00
snipe b6a7fd1cec Run production assets - because modern web development. Sigh. 2018-01-09 20:18:49 -08:00
snipe 6245f92e16 Merge branch 'develop' 2018-01-09 20:12:44 -08:00
snipe 0abab2107c Fixed #4779 - show selected filename on filepicker 2018-01-09 20:12:07 -08:00
snipe afc7116260 Fixed #4778 - added notes to asset model view 2018-01-09 20:00:06 -08:00
Geoff Young 0b3d2b46e0 Add attributes to delete asset file button (#4336)
This adds attributes to the delete file buttons on the View Asset page.
The attributes will fill the confirmation modal that prompts users
before deleting. They also activate a tooltip on the button.
2018-01-03 17:25:50 -08:00
Brandon Daniel Bailey f786e07179 Allow auto increment through the API (#4690)
* Allow auto incrementing asset_id from the API when the setting is enabled

* Cleaned up the if else statement

* Added prefix to the orWhereRaw which causes a database error if the configuration uses a prefix

* Auto incrementing through the API
2018-01-03 17:24:32 -08:00
Daniel Meltzer b2469bb34f Fix double create log on import. (#4706)
* Fix double create log on import.

* Fix code error causing component importer to implode.

* More component importer oldities
2018-01-03 17:22:02 -08:00
Brandon Daniel Bailey b721bfcc84 Added prefix to the orWhereRaw which causes a database error if the configuration uses a prefix (#4703) 2017-12-28 20:09:36 -08:00
Daniel Meltzer f16ce09a7a Importer again (#4702)
* If a user id is provided in the name column of an import, we should assume that it is a user id and check out to it.

* Fix build of vue files.  The location is public/js/build, not public/build

* Ensure a status type is set before allowing submission of an import.

Also expand the status text label to change color based on success/failure.

Fixes #4658

* Use right key to lookup emails when importing users.  Fixes 4619.

* Import serial for components, and make unique matches based on the serial as well as the name.  Fixes #4569

* Set the location_id when importing an item properly.

This moves as well to using the Asset::checkout() method, which should consolidate the logic into a useful spot.
Fixes #4563 (I think)

* Production assets.

* Case insensitive field map guessing and repopulate when changingin import type.
2017-12-28 20:08:45 -08:00
snipe bbe9df306b Merge branch 'develop' 2017-12-26 17:33:06 -08:00
snipe 1bd7392531 Account for audits on deleted assets 2017-12-26 17:32:45 -08:00
snipe 2002dfca17 Merge branch 'develop' 2017-12-26 17:13:49 -08:00
snipe 38c2ecbd0c Fixed migration use 2017-12-26 17:13:26 -08:00
snipe ce97faa8d4 Merge branch 'develop' 2017-12-26 17:11:40 -08:00
snipe 31ca4bff8c Break audit date denorm migrations into two separate migrations 2017-12-26 17:11:08 -08:00
snipe 6f9033b2fd Merge branch 'develop' 2017-12-26 16:49:42 -08:00
snipe 8864f81402 Fixed manufacturer error on printable user page
Manufacturer is not required for accessories, so need to account for that
2017-12-26 16:49:01 -08:00
snipe 71ba1af647 Fixed button class on asset view 2017-12-26 16:48:28 -08:00
snipe b894a4c19a Merge branch 'develop' 2017-12-20 12:36:45 -08:00
snipe c3a44f25fd Fixed #4663 - duplicate manufacturer name in selectlist 2017-12-20 12:32:55 -08:00
snipe 1f36e7997f Bumped version 2017-12-20 03:31:43 -08:00
snipe 33b5c26da5 Bumped hashcount 2017-12-19 22:16:31 -08:00
snipe e5a7e6619f Merge branch 'develop' 2017-12-19 22:15:51 -08:00
snipe d2e2c1c05f Stub and 404 registration routes 2017-12-19 22:14:51 -08:00
snipe 557b8b0ded Merge branch 'develop' 2017-12-19 20:57:46 -08:00
snipe 37d4cf3afb Fixed #4647 - requestable model button not clickable 2017-12-19 20:48:26 -08:00
snipe b716db225f Added “new” buttons for manufacturer and category in asset model creation 2017-12-19 20:30:46 -08:00
snipe fbe093705d Fixed #4640 - add username to user detail 2017-12-19 13:42:34 -08:00
snipe db278e9109 Merge branch 'develop' 2017-12-19 00:48:44 -08:00
snipe 88798435f6 Fixed inefficient query for inventory alerts 2017-12-19 00:32:39 -08:00
snipe 6220f0d8a5 Merge branch 'develop'
# Conflicts:
#	config/version.php
2017-12-15 18:57:21 -08:00
snipe 30716b349b Bumped dev hash 2017-12-15 18:55:56 -08:00
snipe 7a8c8233a2 Fixes #4639 2017-12-15 18:54:38 -08:00
snipe 7a2abcca33 Merge branch 'develop' 2017-12-14 13:00:46 -08:00
Ryan 9a40e5e651 return an error from ldap_search (#4623)
This will return the error from the ldap_search ran in Models/Ldap.php instead of throwing an exception. Users seem to commonly be getting an Exception because of invalid search filters. This will better inform them of that issue without requiring them to enable DEBUG.
2017-12-14 12:57:43 -08:00
snipe 893bcd0533 Merge branch 'develop' 2017-12-12 21:14:41 -08:00
snipe f1a911d305 Fixed ambiguous query on non-super admins with FCS 2017-12-12 21:14:12 -08:00
snipe 8e8d9118e9 Merge branch 'develop' 2017-12-12 16:35:45 -08:00
snipe 9c108873e9 Trying 5.4.35 2017-12-12 16:32:45 -08:00
snipe 6fe5d00e9b Testing laravel 5.4.3 for PHP7.2 bug 2017-12-12 16:23:30 -08:00
snipe a85d5cfe92 Merge branch 'develop' 2017-12-12 12:58:52 -08:00
snipe 6b257cc287 Concat search for full name 2017-12-12 12:52:10 -08:00
snipe 2952497a60 Removed bower components directory
We use npm/webpack now
2017-12-12 11:42:26 -08:00
snipe 9018af4f1d Bumped hash 2017-12-12 10:45:20 -08:00
snipe 5204e84703 Merge branch 'develop'
# Conflicts:
#	config/version.php
2017-12-12 09:25:45 -08:00
snipe 55eaea0110 Derp. 2017-12-12 09:25:06 -08:00
snipe 671a125c62 Bumped hash 2017-12-12 09:24:40 -08:00
snipe eb827cdbe6 Merge branch 'develop' 2017-12-12 09:21:17 -08:00
snipe 5504dd435f Updated transslations 2017-12-12 09:20:57 -08:00
snipe 608bb1b5b1 Fixed #3416 - bulk delete asset models 2017-12-12 09:10:05 -08:00
snipe 88b64034e8 Fixed #3416 - bulk delete asset models 2017-12-12 09:03:37 -08:00
snipe 694c6f3ec6 Merge branch 'develop' 2017-12-12 07:22:30 -08:00
snipe 1d82f80e73 Improved - used “checked out to” string in asset model listing to reflect new polymorphic options 2017-12-12 07:20:06 -08:00
snipe e21fa37254 Added - bulk actions to model asset listings 2017-12-12 07:15:51 -08:00
snipe 1ef44721f5 Improved - disallow delete if not elgible in UI 2017-12-12 07:03:31 -08:00
snipe 528630a8d3 Improvement - make asset, etc totals in company listing sortable 2017-12-12 07:03:09 -08:00
snipe 856a760d89 Improved - disallow deleting manufactureres if there are associated items
This is enforced on the backend - UI imorovement only
2017-12-12 06:52:50 -08:00
snipe 9179b6d9c4 Improved - disallow delete through the GUI if asset model has assets associated
(We prevent this on the backend anyway, but this makes for nicer UI)
2017-12-12 06:49:04 -08:00
snipe 4ce91a4f5d Fixed namespace gate for components - related to #4282 2017-12-12 06:26:37 -08:00
snipe aff93d8f2b Fixed #4589 - Licence deployed to asset issue 2017-12-12 05:43:06 -08:00
snipe e4ab4024c5 Added - changelog searchable in history tab 2017-12-12 05:10:13 -08:00
snipe 612f23f6e0 Added #2893 - track changes on asset edits 2017-12-12 04:59:28 -08:00
snipe 1d543f83d4 Added line spacing between unstyled lists 2017-12-12 04:31:53 -08:00
snipe 88ca852dcf Cleaned up asset observer 2017-12-12 03:40:04 -08:00
snipe 9fe2a7f81d Removed duplicate log entry on asset creation 2017-12-12 03:39:55 -08:00
snipe a988011f0c Merge branch 'develop'
# Conflicts:
#	config/version.php
2017-12-12 03:07:43 -08:00
snipe c816870083 De-norm last audit date so we can display it in the asset listing 2017-12-12 03:03:43 -08:00
snipe c5c46b7283 Removed duplicate deleted logaction
This is handled via observers now
2017-12-12 02:32:45 -08:00
snipe 8bb8306f80 Added restored string 2017-12-12 02:31:46 -08:00
snipe d91e8bfee5 Fixed select2 on setup 2017-12-12 02:31:36 -08:00
snipe 2b3e5c8800 Moved “deleted” alert banner higher on page 2017-12-12 02:31:26 -08:00
snipe 5b00a8ae33 Use specific company_id column name in user search 2017-12-11 22:50:55 -08:00
snipe 5ee6e7f94b Fixed #4613 - Added table prefix to user search DB raw 2017-12-11 22:31:07 -08:00
snipe f90271dae5 Aaaaand one more for #2810. Sigh. 2017-12-08 14:33:12 -08:00
snipe e1423bd9d9 One more fix for #2810 2017-12-08 14:02:27 -08:00
snipe 557714e7b7 Fixed #2810 - checkin fix for licenses 2017-12-08 13:19:10 -08:00
snipe 3df62a200f Fixed manufacturer gates 2017-12-08 13:16:37 -08:00
snipe a65ea639ed Added comments to SnipePermissionsPolicy for clarity 2017-12-07 21:00:09 -08:00
snipe defed52caa Fixed #4596 - manufacturer gate 2017-12-07 20:59:55 -08:00
snipe 035f7a5292 Formatted version 2017-12-07 19:24:03 -08:00
snipe 0ea3100896 Bumped hash 2017-12-07 19:23:34 -08:00
snipe 2e0c2bd190 Add @Gelob as a contributor 2017-12-07 19:20:08 -08:00
snipe ceca76b344 Merge branch 'develop' 2017-12-07 13:21:45 -08:00
snipe a062769672 Check for array key before checking selected state
This is necessary for pre-created groups that don’t have all keys present
2017-12-07 13:21:30 -08:00
Ryan af6a794ae9 fix typo (#4585) 2017-12-06 20:51:37 -08:00
snipe f4ac087c83 Fixed policy namespace 2017-12-06 14:49:52 -08:00
snipe 4898dd8e23 Use ImageUploadRequest $request on user profile update 2017-12-06 14:42:14 -08:00
snipe a090b6a9d2 Use ImageUploadRequest 2017-12-06 14:38:01 -08:00
snipe 023910472c Fixes #2415 - only allow gif, png jpg, svg image uploads 2017-12-06 14:33:52 -08:00
snipe 25bf10b125 Merge branch 'develop' 2017-12-06 11:19:45 -08:00
snipe dfb0c09c51 Fixed #4581 - renamed print method 2017-12-06 11:17:42 -08:00
snipe 41c8d6302a Merge branch 'develop' 2017-12-05 18:17:32 -08:00
snipe 83547e3fed Prepopulate ther groups array on create 2017-12-05 18:17:11 -08:00
snipe 0d92ffc7ed Merge branch 'develop' 2017-12-05 18:13:08 -08:00
snipe 3d0525bc51 Removed debugging info 2017-12-05 18:11:59 -08:00
snipe 808cd0f728 Nicer groups permission edit UI 2017-12-05 18:11:06 -08:00
snipe f5b3df697c Better select/unselect all javascript for permissions 2017-12-05 18:10:35 -08:00
snipe 29a36b5d1c Do not allow null id on group edit 2017-12-05 16:49:26 -08:00
snipe ec131a7416 Updated account licenses 2017-12-05 16:27:02 -08:00
snipe 3da49ceb60 Standardize hidden key format 2017-12-05 16:26:39 -08:00
snipe a19cef07bf Check for gate on license key display 2017-12-05 16:26:23 -08:00
snipe c39e6d7006 Fixed #4576 - licence checkout gate 2017-12-05 15:04:10 -08:00
snipe 60f6895919 Remove version from asset table to persist column selections 2017-12-05 14:50:38 -08:00
snipe bfa4812482 Exclude company on filter 2017-12-05 14:23:46 -08:00
snipe a083cdba18 Merge branch 'develop' 2017-12-05 14:04:55 -08:00
snipe 438f484d68 Removed duplicate purchase cost column 2017-12-05 14:03:08 -08:00
snipe f95d780fcf Include purchase cost column if depreciation is selected 2017-12-05 14:02:43 -08:00
snipe 79fe092c81 Merge branch 'develop'
# Conflicts:
#	config/version.php
2017-12-05 13:20:39 -08:00
snipe 027f6a7c12 Bumped hash 2017-12-05 13:18:52 -08:00
snipe 76fe2af0af Fixed #4444 - Added EOL back into asset lsiting and custom report 2017-12-05 13:03:11 -08:00
snipe e490185533 Fixed EOL in custom report 2017-12-05 12:54:19 -08:00
snipe deba4d2b81 Added consumables tio printable output 2017-12-05 12:37:42 -08:00
snipe a8cc29f062 Added #2562 - print view of all assigned inventory 2017-12-05 12:34:16 -08:00
snipe c9e6a75ea8 Make sure there is a valid status label associated withthe asset when checking if deployable 2017-12-05 11:28:48 -08:00
snipe 7efa7ec03f Starter print template for all assets assigned to a user 2017-12-05 01:55:24 -08:00
snipe 9eef7a94ab Fixed #4557 - added missing fields in components/consumables list view 2017-12-05 00:40:30 -08:00
3844 changed files with 44894 additions and 457756 deletions
+64
View File
@@ -829,6 +829,70 @@
"test",
"code"
]
},
{
"login": "Gelob",
"name": "Ryan",
"avatar_url": "https://avatars3.githubusercontent.com/u/422752?v=4",
"profile": "https://github.com/Gelob",
"contributions": [
"doc"
]
},
{
"login": "vcordes79",
"name": "vcordes79",
"avatar_url": "https://avatars1.githubusercontent.com/u/10672546?v=4",
"profile": "https://github.com/vcordes79",
"contributions": [
"code"
]
},
{
"login": "fordster78",
"name": "fordster78",
"avatar_url": "https://avatars3.githubusercontent.com/u/27958330?v=4",
"profile": "https://github.com/fordster78",
"contributions": [
"code"
]
},
{
"login": "CronKz",
"name": "CronKz",
"avatar_url": "https://avatars0.githubusercontent.com/u/34064225?v=4",
"profile": "https://github.com/CronKz",
"contributions": [
"code"
]
},
{
"login": "tdb",
"name": "Tim Bishop",
"avatar_url": "https://avatars1.githubusercontent.com/u/585486?v=4",
"profile": "https://github.com/tdb",
"contributions": [
"code"
]
},
{
"login": "seanmcilvenna",
"name": "Sean McIlvenna",
"avatar_url": "https://avatars2.githubusercontent.com/u/5384694?v=4",
"profile": "https://www.seanmcilvenna.com",
"contributions": [
"code"
]
},
{
"login": "cepacs",
"name": "cepacs",
"avatar_url": "https://avatars3.githubusercontent.com/u/36515590?v=4",
"profile": "https://github.com/cepacs",
"contributions": [
"bug",
"doc"
]
}
]
}
+1
View File
@@ -105,3 +105,4 @@ APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
ALLOW_IFRAMING=false
APP_CIPHER=AES-256-CBC
GOOGLE_MAPS_API=
BACKUP_ENV=true
+2 -2
View File
@@ -1,8 +1,8 @@
APP_ENV=testing
APP_DEBUG=true
APP_URL=http://snipe-it.localapp
DB_CONNECTION=sqlite_testing
DB_DEFAULT=sqlite_testing
DB_CONNECTION=mysql
DB_DEFAULT=mysql
DB_HOST=localhost
DB_DATABASE=snipeittests
DB_USERNAME=snipeit
+19
View File
@@ -0,0 +1,19 @@
APP_ENV=testing
APP_DEBUG=true
APP_URL=http://snipe-it.localapp
DB_CONNECTION=sqlite_testing
DB_DEFAULT=sqlite_testing
DB_HOST=localhost
APP_KEY=base64:tu9NRh/a6+dCXBDGvg0Gv/0TcABnFsbT4AKxrr8mwQo=
# --------------------------------------------
# OPTIONAL: LOGIN THROTTLING
# (LOGIN_LOCKOUT_DURATIONin minutes)
# --------------------------------------------
LOGIN_MAX_ATTEMPTS=1000000
LOGIN_LOCKOUT_DURATION=100000000
MAIL_DRIVER=log
MAIL_FROM_ADDR=you@example.com
MAIL_FROM_NAME=Snipe-IT
+2 -2
View File
@@ -28,8 +28,8 @@
- What specific Snipe-IT page you're on, and what specific element you're interacting with to trigger the error
- If a stacktrace is provided in the error, include that too.
- Any errors that appear in your browser's error console.
- Confirm whether the error is reproduceable on the demo: https://snipeitapp.com/demo.
- Include any additional information you can find in `app/storage/logs` and your webserver's logs.
- Confirm whether the error is reproducible on the demo: https://snipeitapp.com/demo.
- Include any additional information you can find in `storage/logs` and your webserver's logs.
- Include what you've done so far in the installation, and if you got any error messages along the way.
- Indicate whether or not you've manually edited any data directly in the database
+20
View File
@@ -0,0 +1,20 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- :woman_technologist: ready for dev
- :moneybag: bounty
- :hand: bug
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
+1
View File
@@ -0,0 +1 @@
memory_limit= 2048M
+12 -3
View File
@@ -1,4 +1,7 @@
addons:
code_climate:
repo_token:
secure: "C/bUAEpwfZB82dkzI2Nxx3PW5w/BzbKkSyCkp6YjT046jD2/QKvz6ngCFlt3tAWV11TXWFI6D8DzkMmdWOrQl3SGlPZXRD8QOvCiz0HiGMDvlxjAaPaQecGaQZdx/H4m6xTUXRNUVaYmxlMgkkFCWhAp+HZDs0iyOEVamp0Jszg="
hosts:
- localhost
sudo: false
@@ -13,9 +16,12 @@ services:
php:
- 5.6
- 7.0
# - 7.2 DISABLE Temporarily until we fix the count(null) bugs
- 7.1.4
# execute any number of scripts before the test run, custom env's are available as variables
before_script:
- phpenv config-add .github/travis-memory.ini
- phantomjs --webdriver=4444 &
- sleep 4
- mysql -e 'CREATE DATABASE snipeit_unit;'
@@ -45,9 +51,12 @@ before_script:
script:
- ./vendor/bin/codecept run unit
# - ./vendor/bin/codecept run acceptance --env=testing-ci
- ./vendor/bin/codecept run functional --env=functional-travis
#script: ./vendor/bin/codecept run
- ./vendor/bin/codecept run api --env=testing-ci
- ./vendor/bin/codecept run functional --env=functional-travis -g func1
- ./vendor/bin/codecept run functional --env=functional-travis -g func2
- ./vendor/bin/codecept run api --env=functional-travis
after_script:
- vendor/bin/test-reporter
after_success:
- codecov
+16 -3
View File
@@ -1,5 +1,5 @@
[![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=develop)](https://travis-ci.org/snipe/snipe-it) [![Stories in Ready](https://badge.waffle.io/snipe/snipe-it.png?label=ready+for+dev&title=Ready+for+development)](http://waffle.io/snipe/snipe-it) [![Maintenance](https://img.shields.io/maintenance/yes/2017.svg)]() [![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/snipeyhead.svg?style=social)](https://twitter.com/snipeyhead) [![Zenhub](https://img.shields.io/badge/Shipping_faster_with-ZenHub-5e60ba.svg)](https://zenhub.io) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors)
[![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/snipeyhead.svg?style=social)](https://twitter.com/snipeyhead) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-96-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
@@ -50,6 +50,18 @@ Please see the [translations documentation](https://snipe-it.readme.io/docs/tran
-----
### Libraries, Modules & Related Projects
Since the release of the JSON REST API, several third-party developers have been developing modules and libraries to work with Snipe-IT.
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
- [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)
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. :)
-----
### 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:
@@ -68,7 +80,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars2.githubusercontent.com/u/857740?v=3" width="110px;"/><br /><sub>Gil Rutkowski</sub>](http://FlashingCursor.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [<img src="https://avatars3.githubusercontent.com/u/129360?v=3" width="110px;"/><br /><sub>Desmond Morris</sub>](http://www.desmondmorris.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [<img src="https://avatars2.githubusercontent.com/u/52936?v=3" width="110px;"/><br /><sub>Nick Peelman</sub>](http://peelman.us)<br />[💻](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [<img src="https://avatars0.githubusercontent.com/u/53161?v=3" width="110px;"/><br /><sub>Abraham Vegh</sub>](https://abrahamvegh.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [<img src="https://avatars0.githubusercontent.com/u/2818680?v=3" width="110px;"/><br /><sub>Mohamed Rashid</sub>](https://github.com/rashivkp)<br />[📖](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1509456?v=3" width="110px;"/><br /><sub>Kasey</sub>](http://hinchk.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [<img src="https://avatars2.githubusercontent.com/u/10522541?v=3" width="110px;"/><br /><sub>Brett</sub>](https://github.com/BrettFagerlund)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") |
| [<img src="https://avatars2.githubusercontent.com/u/16108587?v=3" width="110px;"/><br /><sub>Jason Spriggs</sub>](http://jasonspriggs.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [<img src="https://avatars2.githubusercontent.com/u/1134568?v=3" width="110px;"/><br /><sub>Nate Felton</sub>](http://n8felton.wordpress.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [<img src="https://avatars2.githubusercontent.com/u/14036694?v=3" width="110px;"/><br /><sub>Manasses Ferreira</sub>](http://homepages.dcc.ufmg.br/~manassesferreira)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [<img src="https://avatars0.githubusercontent.com/u/15913949?v=3" width="110px;"/><br /><sub>Steve</sub>](https://github.com/steveelwood)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [<img src="https://avatars1.githubusercontent.com/u/3361683?v=3" width="110px;"/><br /><sub>matc</sub>](http://twitter.com/matc)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [<img src="https://avatars3.githubusercontent.com/u/7405702?v=3" width="110px;"/><br /><sub>Cole R. Davis</sub>](http://www.davisracingteam.com)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [<img src="https://avatars2.githubusercontent.com/u/10167681?v=3" width="110px;"/><br /><sub>gibsonjoshua55</sub>](https://github.com/gibsonjoshua55)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") |
| [<img src="https://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [<img src="https://avatars1.githubusercontent.com/u/6551003?v=4" width="110px;"/><br /><sub>Richard Hofman</sub>](https://github.com/richardhofman6)<br />[💻](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [<img src="https://avatars0.githubusercontent.com/u/3697569?v=4" width="110px;"/><br /><sub>gizzmojr</sub>](https://github.com/gizzmojr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [<img src="https://avatars3.githubusercontent.com/u/404729?v=4" width="110px;"/><br /><sub>Jenny Li</sub>](https://github.com/imjennyli)<br />[📖](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/869227?v=4" width="110px;"/><br /><sub>Geoff Young</sub>](https://github.com/GeoffYoung)<br />[💻](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [<img src="https://avatars3.githubusercontent.com/u/1068477?v=4" width="110px;"/><br /><sub>Elliot Blackburn</sub>](http://www.elliotblackburn.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18545156?v=4" width="110px;"/><br /><sub>Lawrence</sub>](https://github.com/TheVakman)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>uknzaeinozpas</sub>](https://github.com/uknzaeinozpas)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [💻](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") |
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18545156?v=4" width="110px;"/><br /><sub>Lawrence</sub>](https://github.com/TheVakman)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>uknzaeinozpas</sub>](https://github.com/uknzaeinozpas)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [💻](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") | [<img src="https://avatars3.githubusercontent.com/u/422752?v=4" width="110px;"/><br /><sub>Ryan</sub>](https://github.com/Gelob)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Gelob "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/10672546?v=4" width="110px;"/><br /><sub>vcordes79</sub>](https://github.com/vcordes79)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vcordes79 "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/27958330?v=4" width="110px;"/><br /><sub>fordster78</sub>](https://github.com/fordster78)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [<img src="https://avatars0.githubusercontent.com/u/34064225?v=4" width="110px;"/><br /><sub>CronKz</sub>](https://github.com/CronKz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") | [<img src="https://avatars1.githubusercontent.com/u/585486?v=4" width="110px;"/><br /><sub>Tim Bishop</sub>](https://github.com/tdb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [<img src="https://avatars2.githubusercontent.com/u/5384694?v=4" width="110px;"/><br /><sub>Sean McIlvenna</sub>](https://www.seanmcilvenna.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [<img src="https://avatars3.githubusercontent.com/u/36515590?v=4" width="110px;"/><br /><sub>cepacs</sub>](https://github.com/cepacs)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [📖](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
+69 -44
View File
@@ -16,7 +16,7 @@ class LdapSync extends Command
*
* @var string
*/
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--summary} {--json_summary}';
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--summary} {--json_summary}';
/**
* The console command description.
@@ -67,27 +67,25 @@ class LdapSync extends Command
$summary = array();
$results = Ldap::findLdapUsers();
// 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"]);
}
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (sizeof($ldap_ou_locations) > 0) {
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
try {
if ($this->option('base_dn') != '') {
$search_base = $this->option('base_dn');
LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
} else {
$search_base = null;
}
$results = Ldap::findLdapUsers($search_base);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$this->info(json_encode($json_summary));
}
LOG::error($e);
return [];
}
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
}
/* Determine which location to assign users to by default. */
$location = NULL;
if ($this->option('location')!='') {
$location = Location::where('name', '=', $this->option('location'))->first();
@@ -97,40 +95,61 @@ class LdapSync extends Command
$location = Location::where('id', '=', $this->option('location_id'))->first();
LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
} else {
$location = NULL;
}
}
if (!isset($location)) {
LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
}
// Grab subsets based on location-specific DNs, and overwrite location for these users.
foreach ($ldap_ou_locations as $ldap_loc) {
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
$usernames = array();
for ($i = 0; $i < $location_users["count"]; $i++) {
$location_users[$i]["ldap_location_override"] = true;
$location_users[$i]["location_id"] = $ldap_loc["id"];
$usernames[] = $location_users[$i][$ldap_result_username][0];
/* Process locations with explicitly defined OUs, if doing a full import. */
if ($this->option('base_dn')=='') {
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
$ldap_ou_lengths = array();
foreach ($ldap_ou_locations as $location) {
$ldap_ou_lengths[] = strlen($location["ldap_ou"]);
}
// Delete located users from the general group.
foreach ($results as $key => $generic_entry) {
if (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
unset($results[$key]);
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (sizeof($ldap_ou_locations) > 0) {
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
}
// Grab subsets based on location-specific DNs, and overwrite location for these users.
foreach ($ldap_ou_locations as $ldap_loc) {
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
$usernames = array();
for ($i = 0; $i < $location_users["count"]; $i++) {
$location_users[$i]["ldap_location_override"] = true;
$location_users[$i]["location_id"] = $ldap_loc["id"];
$usernames[] = $location_users[$i][$ldap_result_username][0];
}
}
$global_count = $results['count'];
$results = array_merge($location_users, $results);
$results['count'] = $global_count;
// Delete located users from the general group.
foreach ($results as $key => $generic_entry) {
if (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
unset($results[$key]);
}
}
$global_count = $results['count'];
$results = array_merge($location_users, $results);
$results['count'] = $global_count;
}
}
/* Create user account entries in Snipe-IT */
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$pass = bcrypt($tmp_pass);
for ($i = 0; $i < $results["count"]; $i++) {
if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == "TRUE") {
@@ -170,8 +189,14 @@ class LdapSync extends Command
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
} else if ($location) {
$user->location_id = e($location->id);
} elseif ((isset($location)) && (!empty($location))) {
if ((is_array($location)) && (array_key_exists('id', $location))) {
$user->location_id = $location['id'];
} elseif (is_object($location)) {
$user->location_id = $location->id;
}
}
$user->notes = 'Imported from LDAP';
@@ -198,9 +223,9 @@ class LdapSync extends Command
if ($this->option('summary')) {
for ($x = 0; $x < count($summary); $x++) {
if ($summary[$x]['status']=='error') {
$this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].' was not imported: '.$summary[$x]['note']);
$this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was not imported: '.$summary[$x]['note']);
} else {
$this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].' was '.strtoupper($summary[$x]['createorupdate']).'.');
$this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was '.strtoupper($summary[$x]['createorupdate']).'.');
}
}
} else if ($this->option('json_summary')) {
+71 -14
View File
@@ -235,7 +235,7 @@ class Helper
*/
public static function statusLabelList()
{
$statuslabel_list = array('' => trans('general.select_statuslabel')) + Statuslabel::orderBy('deployable', 'desc')
$statuslabel_list = array('' => trans('general.select_statuslabel')) + Statuslabel::orderBy('default_label', 'desc')->orderBy('name','asc')->orderBy('deployable','desc')
->pluck('name', 'id')->toArray();
return $statuslabel_list;
}
@@ -460,19 +460,19 @@ class Helper
*/
public static function checkLowInventory()
{
$consumables = Consumable::with('users')->whereNotNull('min_amt')->get();
$accessories = Accessory::with('users')->whereNotNull('min_amt')->get();
$components = Component::with('assets')->whereNotNull('min_amt')->get();
$consumables = Consumable::withCount('consumableAssignments')->whereNotNull('min_amt')->get();
$accessories = Accessory::withCount('users')->whereNotNull('min_amt')->get();
$components = Component::withCount('assets')->whereNotNull('min_amt')->get();
$avail_consumables = 0;
$items_array = array();
$all_count = 0;
foreach ($consumables as $consumable) {
$avail = $consumable->numRemaining();
$avail = $consumable->qty - $consumable->consumable_assignment_count; //$consumable->numRemaining();
if ($avail < ($consumable->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($consumable->qty > 0) {
$percent = number_format((($consumable->numRemaining() / $consumable->qty) * 100), 0);
$percent = number_format((($avail / $consumable->qty) * 100), 0);
} else {
$percent = 100;
}
@@ -481,7 +481,7 @@ class Helper
$items_array[$all_count]['name'] = $consumable->name;
$items_array[$all_count]['type'] = 'consumables';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$consumable->numRemaining();
$items_array[$all_count]['remaining'] = $avail;
$items_array[$all_count]['min_amt']=$consumable->min_amt;
$all_count++;
}
@@ -490,11 +490,11 @@ class Helper
}
foreach ($accessories as $accessory) {
$avail = $accessory->numRemaining();
$avail = $accessory->qty - $accessory->users_count;
if ($avail < ($accessory->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($accessory->qty > 0) {
$percent = number_format((($accessory->numRemaining() / $accessory->qty) * 100), 0);
$percent = number_format((($avail / $accessory->qty) * 100), 0);
} else {
$percent = 100;
}
@@ -503,7 +503,7 @@ class Helper
$items_array[$all_count]['name'] = $accessory->name;
$items_array[$all_count]['type'] = 'accessories';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$accessory->numRemaining();
$items_array[$all_count]['remaining'] = $avail;
$items_array[$all_count]['min_amt']=$accessory->min_amt;
$all_count++;
}
@@ -511,10 +511,10 @@ class Helper
}
foreach ($components as $component) {
$avail = $component->numRemaining();
$avail = $component->qty - $component->assets_count;
if ($avail < ($component->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($component->qty > 0) {
$percent = number_format((($component->numRemaining() / $component->qty) * 100), 0);
$percent = number_format((($avail / $component->qty) * 100), 0);
} else {
$percent = 100;
}
@@ -523,7 +523,7 @@ class Helper
$items_array[$all_count]['name'] = $component->name;
$items_array[$all_count]['type'] = 'components';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$component->numRemaining();
$items_array[$all_count]['remaining'] = $avail;
$items_array[$all_count]['min_amt']=$component->min_amt;
$all_count++;
}
@@ -690,7 +690,7 @@ class Helper
$array['status'] = $status;
$array['messages'] = $messages;
if (($messages) && (count($messages) > 0)) {
if (($messages) && (is_array($messages)) && (count($messages) > 0)) {
$array['messages'] = $messages;
}
($payload) ? $array['payload'] = $payload : $array['payload'] = null;
@@ -731,5 +731,62 @@ class Helper
}
// Nicked from Drupal :)
// Returns a file size limit in bytes based on the PHP upload_max_filesize
// and post_max_size
public static function file_upload_max_size() {
static $max_size = -1;
if ($max_size < 0) {
// Start with post_max_size.
$post_max_size = Helper::parse_size(ini_get('post_max_size'));
if ($post_max_size > 0) {
$max_size = $post_max_size;
}
// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
$upload_max = Helper::parse_size(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
$max_size = $upload_max;
}
}
return $max_size;
}
public static function file_upload_max_size_readable() {
static $max_size = -1;
if ($max_size < 0) {
// Start with post_max_size.
$post_max_size = Helper::parse_size(ini_get('post_max_size'));
if ($post_max_size > 0) {
$max_size = ini_get('post_max_size');
}
// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
$upload_max = Helper::parse_size(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
$max_size = ini_get('upload_max_filesize');
}
}
return $max_size;
}
public static function parse_size($size) {
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
$size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
if ($unit) {
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
}
else {
return round($size);
}
}
}
@@ -369,7 +369,7 @@ class AccessoriesController extends Controller
// Check if the accessory exists
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$accessory = Accessory::find($accessory_user->accessory_id);
@@ -387,6 +387,7 @@ class AccessoriesController extends Controller
$data['log_id'] = $logaction->id;
$data['first_name'] = e($user->first_name);
$data['last_name'] = e($user->last_name);
$data['item_name'] = e($accessory->name);
$data['checkin_date'] = e($logaction->created_at);
$data['item_tag'] = '';
@@ -40,10 +40,26 @@ class AssetMaintenancesController extends Controller
$maintenances = $maintenances->TextSearch(e($request->input('search')));
}
if ($request->has('asset_id')) {
$maintenances->where('asset_id', '=', $request->input('asset_id'));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['id','title','asset_maintenance_time','asset_maintenance_type','cost','start_date','completion_date','notes','user_id'];
$allowed_columns = [
'id',
'title',
'asset_maintenance_time',
'asset_maintenance_type',
'cost',
'start_date',
'completion_date',
'notes',
'asset_tag',
'asset_name',
'user_id'
];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
@@ -51,6 +67,12 @@ class AssetMaintenancesController extends Controller
case 'user_id':
$maintenances = $maintenances->OrderAdmin($order);
break;
case 'asset_tag':
$maintenances = $maintenances->OrderByTag($order);
break;
case 'asset_name':
$maintenances = $maintenances->OrderByAssetName($order);
break;
default:
$maintenances = $maintenances->orderBy($sort, $order);
break;
@@ -30,20 +30,35 @@ class AssetModelsController extends Controller
public function index(Request $request)
{
$this->authorize('view', AssetModel::class);
$allowed_columns = ['id','image','name','model_number','eol','notes','created_at','manufacturer'];
$allowed_columns = ['id','image','name','model_number','eol','notes','created_at','manufacturer','assets_count'];
$assetmodels = AssetModel::select(['models.id','models.image','models.name','model_number','eol','models.notes','models.created_at','category_id','manufacturer_id','depreciation_id','fieldset_id', 'models.deleted_at'])
$assetmodels = AssetModel::select([
'models.id',
'models.image',
'models.name',
'model_number',
'eol',
'models.notes',
'models.created_at',
'category_id',
'manufacturer_id',
'depreciation_id',
'fieldset_id',
'models.deleted_at',
'models.updated_at',
])
->with('category','depreciation', 'manufacturer','fieldset')
->withCount('assets');
if ($request->has('search')) {
$assetmodels->TextSearch($request->input('search'));
}
if ($request->has('status')) {
$assetmodels->onlyTrashed();
}
if ($request->has('search')) {
$assetmodels->TextSearch($request->input('search'));
}
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
@@ -60,6 +75,7 @@ class AssetModelsController extends Controller
}
$total = $assetmodels->count();
$assetmodels = $assetmodels->skip($offset)->take($limit)->get();
return (new AssetModelsTransformer)->transformAssetModels($assetmodels, $total);
@@ -135,7 +151,7 @@ class AssetModelsController extends Controller
$assetmodel->fieldset_id = $request->get("custom_fieldset_id");
if ($assetmodel->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/assetmodels/message.update.success')));
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.update.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
@@ -168,7 +184,7 @@ class AssetModelsController extends Controller
}
$assetmodel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/assetmodels/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/models/message.delete.success')));
}
@@ -192,6 +208,7 @@ class AssetModelsController extends Controller
'models.category_id',
])->with('manufacturer','category');
$settings = \App\Models\Setting::getSettings();
if ($request->has('search')) {
$assetmodels = $assetmodels->SearchByManufacturerOrCat($request->input('search'));
@@ -200,8 +217,24 @@ class AssetModelsController extends Controller
$assetmodels = $assetmodels->OrderCategory('ASC')->OrderManufacturer('ASC')->orderby('models.name', 'asc')->orderby('models.model_number', 'asc')->paginate(50);
foreach ($assetmodels as $assetmodel) {
$assetmodel->use_text = (($assetmodel->category) ? e($assetmodel->category->name) : '').': '.(($assetmodel->manufacturer) ? e($assetmodel->manufacturer->name) : '').' '.$assetmodel->present()->modelName;
$assetmodel->use_image = ($assetmodel->image) ? url('/').'/uploads/models/'.$assetmodel->image : null;
$assetmodel->use_text = '';
if ($settings->modellistCheckedValue('category')) {
$assetmodel->use_text .= (($assetmodel->category) ? e($assetmodel->category->name).' - ' : '');
}
if ($settings->modellistCheckedValue('manufacturer')) {
$assetmodel->use_text .= (($assetmodel->manufacturer) ? e($assetmodel->manufacturer->name).' ' : '');
}
$assetmodel->use_text .= e($assetmodel->name);
if (($settings->modellistCheckedValue('model_number')) && ($assetmodel->model_number!='')) {
$assetmodel->use_text .= ' (#'.e($assetmodel->model_number).')';
}
$assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? url('/').'/uploads/models/'.$assetmodel->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($assetmodels);
+61 -35
View File
@@ -54,7 +54,9 @@ class AssetsController extends Controller
*/
public function index(Request $request)
{
$this->authorize('index', Asset::class);
$settings = Setting::getSettings();
$allowed_columns = [
'id',
@@ -72,34 +74,34 @@ class AssetsController extends Controller
'updated_at',
'purchase_date',
'purchase_cost',
'last_audit_date',
'next_audit_date',
'warranty_months',
];
$filter = array();
if ($request->has('filter')) {
$filter = json_decode($request->input('filter'));
}
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
foreach ($all_custom_fields as $field) {
$allowed_columns[]=$field->db_column_name();
}
$assets = Company::scopeCompanyables(Asset::select('assets.*'))->with(
'location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
if (count($filter) > 0) {
$assets->ByFilter($filter);
} elseif ($request->has('search')) {
$assets->TextSearch($request->input('search'));
}
// These are used by the API to query against specific ID numbers
// 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')) {
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
@@ -114,12 +116,18 @@ class AssetsController extends Controller
if ($request->has('location_id')) {
$assets->where('assets.location_id', '=', $request->input('location_id'));
// dd($assets->toSql());
}
if ($request->has('supplier_id')) {
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
}
if (($request->has('assigned_to')) && ($request->has('assigned_type'))) {
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
->where('assets.assigned_type', '=', $request->input('assigned_type'));
}
if ($request->has('company_id')) {
$assets->where('assets.company_id', '=', $request->input('company_id'));
}
@@ -138,7 +146,6 @@ class AssetsController extends Controller
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
// This is used by the sidenav, mostly
// We switched from using query scopes here because of a Laravel bug
@@ -191,11 +198,27 @@ class AssetsController extends Controller
$assets->where('assets.assigned_to', '>', '0');
break;
default:
// 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")
->where('status_alias.archived', '=', 0);
});
if ((!$request->has('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")
->where('status_alias.archived', '=', 0);
});
// If there is a status ID, don't take show_archived_in_list into consideration
} else {
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id");
});
}
}
if (count($filter) > 0) {
$assets->ByFilter($filter);
} elseif ($request->has('search')) {
$assets->TextSearch($request->input('search'));
}
@@ -227,6 +250,8 @@ class AssetsController extends Controller
break;
case 'location':
$assets->OrderLocation($order);
case 'rtd_location':
$assets->OrderRtdLocation($order);
break;
case 'status_label':
$assets->OrderStatus($order);
@@ -241,7 +266,8 @@ class AssetsController extends Controller
$assets->orderBy($column_sort, $order);
break;
}
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
return (new AssetsTransformer)->transformAssets($assets, $total);
@@ -342,7 +368,7 @@ class AssetsController extends Controller
$asset->model_id = $request->get('model_id');
$asset->order_number = $request->get('order_number');
$asset->notes = $request->get('notes');
$asset->asset_tag = $request->get('asset_tag');
$asset->asset_tag = $request->get('asset_tag', Asset::autoincrement_asset());
$asset->user_id = Auth::id();
$asset->archived = '0';
$asset->physical = '1';
@@ -394,7 +420,7 @@ class AssetsController extends Controller
*/
public function update(Request $request, $id)
{
$this->authorize('create', Asset::class);
$this->authorize('edit', Asset::class);
if ($asset = Asset::find($id)) {
($request->has('model_id')) ?
@@ -434,26 +460,24 @@ class AssetsController extends Controller
($request->has('company_id')) ?
$asset->company_id = Company::getIdForCurrentUser($request->get('company_id')) : '';
if ($request->has('model_id')) {
if (($model = AssetModel::find($request->get('model_id'))) && (isset($model->fieldset))) {
foreach ($model->fieldset->fields as $field) {
if ($request->has($field->convertUnicodeDbSlug())) {
$asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug()));
}
// 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 ($asset->save()) {
if ($request->get('assigned_user')) {
$target = User::find(request('assigned_user'));
$location = $target->location_id;
} elseif ($request->get('assigned_asset')) {
$target = Asset::find(request('assigned_asset'));
$location = $target->location_id;
} elseif ($request->get('assigned_location')) {
$target = Location::find(request('assigned_location'));
if (($request->has('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')))) {
$location = $target->location_id;
} elseif (($request->has('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
$location = $target->id;
}
@@ -533,7 +557,7 @@ class AssetsController extends Controller
$error_payload['target_type'] = 'location';
} elseif (request('checkout_to_type')=='asset') {
$target = Asset::where('id','!=',$assetId)->find(request('assigned_asset'));
$target = Asset::where('id','!=',$asset_id)->find(request('assigned_asset'));
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
if ($target->location_id!='') {
@@ -612,8 +636,6 @@ class AssetsController extends Controller
$asset->location_id = $request->input('location_id');
}
$asset->location_id = $asset->rtd_location_id;
if (Input::has('status_id')) {
$asset->status_id = e(Input::get('status_id'));
}
@@ -675,7 +697,11 @@ class AssetsController extends Controller
if ($asset) {
// We don't want to log this as a normal update, so let's bypass that
$asset->unsetEventDispatcher();
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d h:i:s');
if ($asset->save()) {
$log = $asset->logAudit(request('note'),request('location_id'));
return response()->json(Helper::formatStandardApiResponse('success', [
@@ -22,12 +22,20 @@ class CompaniesController extends Controller
{
$this->authorize('view', Company::class);
$allowed_columns = ['id','name'];
$allowed_columns = [
'id',
'name',
'created_at',
'updated_at',
'users_count',
'assets_count',
'licenses_count',
'accessories_count',
'consumables_count',
'components_count',
];
$companies = Company::withCount('assets','licenses','accessories','consumables','components','users')
->withCount('users')->withCount('users')->withCount('assets')
->withCount('licenses')->withCount('accessories')
->withCount('consumables')->withCount('components');
$companies = Company::withCount('assets','licenses','accessories','consumables','components','users');
if ($request->has('search')) {
$companies->TextSearch($request->input('search'));
@@ -31,6 +31,10 @@ class ComponentsController extends Controller
$components = $components->TextSearch($request->input('search'));
}
if ($request->has('company_id')) {
$components->where('company_id','=',$request->input('company_id'));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
@@ -89,13 +93,11 @@ class ComponentsController extends Controller
public function show($id)
{
$this->authorize('view', Component::class);
$component = Component::find($id);
$component = Component::findOrFail($id);
if ($component) {
return (new ComponentsTransformer)->transformComponent($component);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.does_not_exist')));
}
@@ -149,7 +151,7 @@ class ComponentsController extends Controller
*/
public function getAssets(Request $request, $id)
{
$this->authorize('index', Asset::class);
$this->authorize('view', \App\Models\Asset::class);
$component = Component::findOrFail($id);
$assets = $component->assets();
@@ -2,11 +2,14 @@
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\CustomFieldsTransformer;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use Illuminate\Http\Request;
use Validator;
use Illuminate\Validation\Rule;
class CustomFieldsController extends Controller
{
@@ -27,6 +30,81 @@ class CustomFieldsController extends Controller
$total = count($fields);
return (new CustomFieldsTransformer)->transformCustomFields($fields, $total);
}
/**
* Shows the given field
* @author [V. Cordes] [<volker@fdatek.de>]
* @param int $id
* @since [v4.1.10]
* @return View
*/
public function show($id)
{
$this->authorize('show', CustomField::class);
if ($field = CustomField::find($id)) {
return (new CustomFieldsTransformer)->transformCustomField($field);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/custom_fields/message.field.invalid')), 200);
}
/**
* Update the specified field
*
* @author [V. Cordes] [<volker@fdatek.de>]
* @since [v4.1.10]
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$this->authorize('edit', CustomField::class);
$field = CustomField::findOrFail($id);
$data = $request->all();
$validator = Validator::make($data, $field->validationRules());
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
}
$field->fill($data);
if ($field->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $field, trans('admin/custom_fields/message.field.update.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $field->getErrors()));
}
/**
* Store a newly created field.
*
* @author [V. Cordes] [<volker@fdatek.de>]
* @since [v4.1.10]
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->authorize('create', CustomField::class);
$field = new CustomField;
$data = $request->all();
$validator = Validator::make($data, $field->validationRules());
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
}
$field->fill($data);
if ($field->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $field, trans('admin/custom_fields/message.field.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $field->getErrors()));
}
public function postReorder(Request $request, $id)
{
$fieldset = CustomFieldset::find($id);
@@ -47,6 +125,38 @@ class CustomFieldsController extends Controller
}
public function associate(Request $request, $field_id)
{
$this->authorize('edit', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset_id = $request->input('fieldset_id');
foreach ($field->fieldset as $fieldset) {
if ($fieldset->id == $fieldset_id) {
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fieldset->fields()->attach($field->id, ["required" => ($request->input('required') == "on"), "order" => $request->input('order', $fieldset->fields->count())]);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
public function disassociate(Request $request, $field_id)
{
$this->authorize('edit', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset_id = $request->input('fieldset_id');
foreach ($field->fieldset as $fieldset) {
if ($fieldset->id == $fieldset_id) {
$fieldset->fields()->detach($field->id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
/**
* Delete a custom field.
@@ -62,7 +172,7 @@ class CustomFieldsController extends Controller
if ($field->fieldset->count() >0) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Field is in use.'));
}
$field->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.field.delete.success')));
@@ -126,7 +126,7 @@ class CustomFieldsetsController extends Controller
{
$this->authorize('delete', CustomFieldset::class);
$fieldset = CustomFieldset::findOrFail($id);
$modelsCount = $fieldset->models->count();
$fieldsCount = $fieldset->fields->count();
@@ -141,7 +141,23 @@ class CustomFieldsetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, 'Unspecified error'));
}
/**
* Return JSON containing a list of fields belonging to a fieldset.
*
* @author [V. Cordes] [<volker@fdatek.de>]
* @since [v4.1.10]
* @param $fieldsetId
* @return string JSON
*/
public function fields($id)
{
$this->authorize('view', CustomFieldset::class);
$set = CustomFieldset::findOrFail($id);
$fields = $set->fields->get();
return (new CustomFieldsTransformer)->transformCustomFields($fields, $fields->count());
}
}
@@ -22,17 +22,17 @@ class DepartmentsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Department::class);
$allowed_columns = ['id','name','image'];
$allowed_columns = ['id','name','image','users_count'];
$departments = Department::select([
'id',
'name',
'location_id',
'company_id',
'manager_id',
'created_at',
'updated_at',
'image'
'departments.id',
'departments.name',
'departments.location_id',
'departments.company_id',
'departments.manager_id',
'departments.created_at',
'departments.updated_at',
'departments.image'
])->with('users')->with('location')->with('manager')->with('company')->withCount('users');
if ($request->has('search')) {
@@ -43,7 +43,18 @@ class DepartmentsController extends Controller
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$departments->orderBy($sort, $order);
switch ($request->input('sort')) {
case 'location':
$departments->OrderLocation($order);
break;
case 'manager':
$departments->OrderManager($order);
break;
default:
$departments->orderBy($sort, $order);
break;
}
$total = $departments->count();
$departments = $departments->skip($offset)->take($limit)->get();
@@ -20,7 +20,7 @@ class GroupsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Group::class);
$allowed_columns = ['id','name','created_at'];
$allowed_columns = ['id','name','created_at', 'users_count'];
$groups = Group::select('id','name','permissions','created_at','updated_at')->withCount('users');
+30 -5
View File
@@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Session;
use League\Csv\Reader;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Artisan;
use App\Models\Asset;
class ImportController extends Controller
{
@@ -57,6 +58,35 @@ class ImportController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
}
//TODO: is there a lighter way to do this?
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$import->header_row = $reader->fetchOne(0);
//duplicate headers check
$duplicate_headers = [];
for($i = 0; $i<count($import->header_row); $i++) {
$header = $import->header_row[$i];
if(in_array($header, $import->header_row)) {
$found_at = array_search($header, $import->header_row);
if($i > $found_at) {
//avoid reporting duplicates twice, e.g. "1 is same as 17! 17 is same as 1!!!"
//as well as "1 is same as 1!!!" (which is always true)
//has to be > because otherwise the first result of array_search will always be $i itself(!)
array_push($duplicate_headers,"Duplicate header '$header' detected, first at column: ".($found_at+1).", repeats at column: ".($i+1));
}
}
}
if(count($duplicate_headers) > 0) {
return response()->json(Helper::formatStandardApiResponse('error',null, implode("; ",$duplicate_headers)), 500); //should this be '4xx'?
}
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
$date = date('Y-m-d-his');
$fixed_filename = str_slug($file->getClientOriginalName());
try {
@@ -71,11 +101,6 @@ class ImportController extends Controller
$file_name = date('Y-m-d-his').'-'.$fixed_filename;
$import->file_path = $file_name;
$import->filesize = filesize($path.'/'.$file_name);
//TODO: is there a lighter way to do this?
$reader = Reader::createFromPath("{$path}/{$file_name}");
$import->header_row = $reader->fetchOne(0);
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
$import->save();
$results[] = $import;
}
+87 -13
View File
@@ -2,11 +2,15 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Transformers\LicenseSeatsTransformer;
use App\Http\Transformers\LicensesTransformer;
use App\Models\License;
use App\Models\Company;
use App\Models\License;
use App\Models\LicenseSeat;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class LicensesController extends Controller
{
@@ -23,9 +27,6 @@ class LicensesController extends Controller
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'freeSeats', 'supplier')->withCount('freeSeats'));
if ($request->has('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
if ($request->has('company_id')) {
$licenses->where('company_id','=',$request->input('company_id'));
@@ -71,6 +72,12 @@ class LicensesController extends Controller
$licenses->where('supplier_id','=',$request->input('supplier_id'));
}
if ($request->has('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -92,7 +99,8 @@ class LicensesController extends Controller
$licenses = $licenses->orderBy($sort, $order);
break;
}
$total = $licenses->count();
@@ -115,6 +123,14 @@ class LicensesController extends Controller
public function store(Request $request)
{
//
$this->authorize('create', License::class);
$license = new License;
$license->fill($request->all());
if($license->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $license, trans('admin/licenses/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $license->getErrors()));
}
/**
@@ -126,13 +142,10 @@ class LicensesController extends Controller
*/
public function show($id)
{
$license = License::find($id);
if (isset($license->id)) {
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
$this->authorize('view', $license);
return (new LicensesTransformer)->transformLicense($license);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.does_not_exist')), 200);
$this->authorize('view', License::class);
$license = License::findOrFail($id);
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
return (new LicensesTransformer)->transformLicense($license);
}
@@ -148,6 +161,16 @@ class LicensesController extends Controller
public function update(Request $request, $id)
{
//
$this->authorize('edit', License::class);
$license = License::findOrFail($id);
$license->fill($request->all());
if ($license->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $license, trans('admin/licenses/message.update.success')));
}
return Helper::formatStandardApiResponse('error', null, $license->getErrors());
}
/**
@@ -161,5 +184,56 @@ class LicensesController extends Controller
public function destroy($id)
{
//
$license = License::findOrFail($id);
$this->authorize('delete', $license);
if($license->assigned_seats_count == 0) {
// Delete the license and the associated license seats
DB::table('license_seats')
->where('id', $license->id)
->update(array('assigned_to' => null,'asset_id' => null));
$licenseSeats = $license->licenseseats();
$licenseSeats->delete();
$license->delete();
// Redirect to the licenses management page
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/licenses/message.delete.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.assoc_users')));
}
/**
* Get license seat listing
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $licenseId
* @return \Illuminate\Contracts\View\View
*/
public function seats(Request $request, $licenseId)
{
if ($license = License::find($licenseId)) {
$seats = LicenseSeat::where('license_id', $licenseId)->with('license', 'user', 'asset');
$offset = request('offset', 0);
$limit = request('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$total = $seats->count();
$seats = $seats->skip($offset)->take($limit)->get();
if ($seats) {
return (new LicenseSeatsTransformer)->transformLicenseSeats($seats, $total);
}
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.does_not_exist')), 200);
}
}
@@ -23,8 +23,8 @@ class LocationsController extends Controller
$this->authorize('view', Location::class);
$allowed_columns = [
'id','name','address','address2','city','state','country','zip','created_at',
'updated_at','parent_id', 'manager_id','image',
'assigned_assets_count','users_count','assets_count'];
'updated_at','manager_id','image',
'assigned_assets_count','users_count','assets_count','currency'];
$locations = Location::with('parent', 'manager', 'childLocations')->select([
'locations.id',
@@ -49,11 +49,25 @@ class LocationsController extends Controller
$locations = $locations->TextSearch($request->input('search'));
}
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$locations->orderBy($sort, $order);
switch ($request->input('sort')) {
case 'parent':
$locations->OrderParent($order);
break;
case 'manager':
$locations->OrderManager($order);
break;
default:
$locations->orderBy($sort, $order);
break;
}
$total = $locations->count();
$locations = $locations->skip($offset)->take($limit)->get();
@@ -22,17 +22,23 @@ class ManufacturersController extends Controller
public function index(Request $request)
{
$this->authorize('view', Manufacturer::class);
$allowed_columns = ['id','name','url','support_url','support_email','support_phone','created_at','updated_at','image'];
$allowed_columns = ['id','name','url','support_url','support_email','support_phone','created_at','updated_at','image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count'];
$manufacturers = Manufacturer::select(
array('id','name','url','support_url','support_email','support_phone','created_at','updated_at','image')
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');
if ($request->input('deleted')=='true') {
$manufacturers->onlyTrashed();
}
if ($request->has('search')) {
$manufacturers = $manufacturers->TextSearch($request->input('search'));
}
$offset = request('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -42,11 +42,15 @@ class ReportsController extends Controller
$allowed_columns = [
'id',
'created_at'
'created_at',
'target_id',
'user_id',
'action_type',
'note'
];
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
$offset = request('offset', 0);
$limit = request('limit', 50);
$total = $actionlogs->count();
@@ -8,6 +8,9 @@ use App\Models\Ldap;
use Validator;
use App\Models\Setting;
use Mail;
use App\Notifications\SlackTest;
use Notification;
use App\Notifications\MailTest;
class SettingsController extends Controller
{
@@ -96,6 +99,29 @@ class SettingsController extends Controller
}
public function slacktest()
{
if ($settings = Setting::getSettings()->slack_channel=='') {
\Log::debug('Slack is not enabled. Cannot test.');
return response()->json(['message' => 'Slack is not enabled, cannot test.'], 400);
}
\Log::debug('Preparing to test slack connection');
try {
Notification::send($settings = Setting::getSettings(), new SlackTest());
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
\Log::debug('Slack connection failed');
return response()->json(['message' => $e->getMessage()], 400);
}
}
/**
* Test the email configuration
*
@@ -107,11 +133,13 @@ class SettingsController extends Controller
{
if (!config('app.lock_passwords')) {
try {
Mail::send('emails.test', [], function ($m) {
Notification::send(Setting::first(), new MailTest());
/*Mail::send('emails.test', [], function ($m) {
$m->to(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.test_email'));
});
});*/
return response()->json(['message' => 'Mail sent to '.config('mail.reply_to.address')], 200);
} catch (Exception $e) {
return response()->json(['message' => $e->getMessage()], 500);
@@ -22,7 +22,7 @@ class StatuslabelsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Statuslabel::class);
$allowed_columns = ['id','name','created_at', 'assets_count'];
$allowed_columns = ['id','name','created_at', 'assets_count','color','default_label'];
$statuslabels = Statuslabel::withCount('assets');
@@ -56,7 +56,7 @@ class StatuslabelsController extends Controller
$request->except('deployable', 'pending','archived');
if (!$request->has('type')) {
return response()->json(Helper::formatStandardApiResponse('error', null, ["type" => ["Status label type is required."]]));
return response()->json(Helper::formatStandardApiResponse('error', null, ["type" => ["Status label type is required."]]),500);
}
$statuslabel = new Statuslabel;
+64 -28
View File
@@ -28,53 +28,50 @@ class UsersController extends Controller
$this->authorize('view', User::class);
$users = User::select([
'users.id',
'users.employee_num',
'users.two_factor_enrolled',
'users.jobtitle',
'users.email',
'users.phone',
'users.activated',
'users.address',
'users.avatar',
'users.city',
'users.state',
'users.country',
'users.zip',
'users.username',
'users.location_id',
'users.manager_id',
'users.first_name',
'users.last_name',
'users.created_at',
'users.notes',
'users.company_id',
'users.last_login',
'users.country',
'users.created_at',
'users.deleted_at',
'users.department_id',
'users.activated',
'users.avatar',
'users.email',
'users.employee_num',
'users.first_name',
'users.id',
'users.jobtitle',
'users.last_login',
'users.last_name',
'users.location_id',
'users.manager_id',
'users.notes',
'users.permissions',
'users.phone',
'users.state',
'users.two_factor_enrolled',
'users.updated_at',
'users.username',
'users.zip',
])->with('manager', 'groups', 'userloc', 'company', 'department','assets','licenses','accessories','consumables')
->withCount('assets','licenses','accessories','consumables');
$users = Company::scopeCompanyables($users);
if ($request->has('search')) {
$users = $users->TextSearch($request->input('search'));
}
if (($request->has('deleted')) && ($request->input('deleted')=='true')) {
$users = $users->GetDeleted();
}
if ($request->has('company_id')) {
$users = $users->where('company_id', '=', $request->input('company_id'));
$users = $users->where('users.company_id', '=', $request->input('company_id'));
}
if ($request->has('location_id')) {
$users = $users->where('location_id', '=', $request->input('location_id'));
$users = $users->where('users.location_id', '=', $request->input('location_id'));
}
if ($request->has('group_id')) {
$users = $users->ByGroup($request->get('group_id'));
}
@@ -83,6 +80,10 @@ class UsersController extends Controller
$users = $users->where('users.department_id','=',$request->input('department_id'));
}
if ($request->has('search')) {
$users = $users->TextSearch($request->input('search'));
}
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$offset = request('offset', 0);
$limit = request('limit', 20);
@@ -111,6 +112,8 @@ class UsersController extends Controller
$users = $users->orderBy($sort, $order);
break;
}
$total = $users->count();
$users = $users->skip($offset)->take($limit)->get();
return (new UsersTransformer)->transformUsers($users, $total);
@@ -131,6 +134,7 @@ class UsersController extends Controller
$users = User::select(
[
'users.id',
'users.username',
'users.employee_num',
'users.first_name',
'users.last_name',
@@ -159,8 +163,12 @@ class UsersController extends Controller
}
$name_str .= e($user->first_name);
if ($user->username!='') {
$name_str .= ' ('.e($user->username).')';
}
if ($user->employee_num!='') {
$name_str .= ' (#'.e($user->employee_num).')';
$name_str .= ' - #'.e($user->employee_num);
}
$user->use_text = $name_str;
@@ -282,4 +290,32 @@ class UsersController extends Controller
$assets = Asset::where('assigned_to', '=', $id)->with('model')->get();
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
/**
* Reset the user's two-factor status
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $userId
* @return string JSON
*/
public function postTwoFactorReset(Request $request)
{
$this->authorize('edit', User::class);
if ($request->has('id')) {
try {
$user = User::find($request->get('id'));
$user->two_factor_secret = null;
$user->two_factor_enrolled = 0;
$user->save();
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
} catch (\Exception $e) {
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_error')], 500);
}
}
return response()->json(['message' => 'No ID provided'], 500);
}
}
@@ -63,85 +63,6 @@ class AssetMaintenancesController extends Controller
}
/**
* Generates the JSON response for asset maintenances listing view.
*
* @see AssetMaintenancesController::getIndex() method that generates view
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return String JSON
*/
public function getDatatable(Request $request)
{
$maintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company', 'admin');
if (Input::has('search')) {
$maintenances = $maintenances->TextSearch(e($request->input('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['id','title','asset_maintenance_time','asset_maintenance_type','cost','start_date','completion_date','notes','user_id'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
switch ($sort) {
case 'user_id':
$maintenances = $maintenances->OrderAdmin($order);
break;
default:
$maintenances = $maintenances->orderBy($sort, $order);
break;
}
$maintenancesCount = $maintenances->count();
$maintenances = $maintenances->skip($offset)->take($limit)->get();
$rows = array();
$settings = Setting::getSettings();
foreach ($maintenances as $maintenance) {
$actions = '';
if (Gate::allows('update', Asset::class)) {
$actions .= Helper::generateDatatableButton('edit', route('maintenances.edit', $maintenance->id));
$actions .= Helper::generateDatatableButton(
'delete',
route('maintenances.destroy', $maintenance->id),
$enabled = true,
trans('admin/asset_maintenances/message.delete.confirm'),
$maintenance->title
);
}
if (($maintenance->cost) && (isset($maintenance->asset)) && ($maintenance->asset->location) && ($maintenance->asset->location->currency!='')) {
$maintenance_cost = $maintenance->asset->location->currency.$maintenance->cost;
} else {
$maintenance_cost = $settings->default_currency.$maintenance->cost;
}
$rows[] = array(
'id' => $maintenance->id,
'asset_name' => ($maintenance->asset) ? (string)link_to_route('maintenances.show', $maintenance->asset->present()->Name(), ['maintenance' => $maintenance->asset->id]) : 'Deleted Asset' ,
'title' => $maintenance->title,
'notes' => $maintenance->notes,
'supplier' => ($maintenance->supplier) ? (string)link_to_route('suppliers.show', $maintenance->supplier->name, ['maintenance'=>$maintenance->supplier->id]) : 'Deleted Supplier',
'cost' => $maintenance_cost,
'asset_maintenance_type' => e($maintenance->asset_maintenance_type),
'start_date' => $maintenance->start_date,
'asset_maintenance_time' => $maintenance->asset_maintenance_time,
'completion_date' => $maintenance->completion_date,
'user_id' => ($maintenance->admin) ? (string)link_to_route('users.show', $maintenance->admin->present()->fullName(), ['user'=>$maintenance->admin->id]) : '',
'actions' => $actions,
'company' => ($maintenance->asset->company) ? $maintenance->asset->company->name : ''
);
}
$data = array('total' => $maintenancesCount, 'rows' => $rows);
return $data;
}
/**
* Returns a form view to create a new asset maintenance.
@@ -265,9 +186,7 @@ class AssetMaintenancesController extends Controller
// Get Supplier List
// Render the view
return view('asset_maintenances/edit')
->with('asset_list', Helper::detailedAssetList())
->with('selectedAsset', null)
->with('supplier_list', Helper::suppliersList())
->with('assetMaintenanceType', $assetMaintenanceType)
->with('item', $assetMaintenance);
+91 -15
View File
@@ -40,6 +40,7 @@ class AssetModelsController extends Controller
*/
public function index()
{
$this->authorize('index', AssetModel::class);
return view('models/index');
}
@@ -52,6 +53,7 @@ class AssetModelsController extends Controller
*/
public function create()
{
$this->authorize('create', AssetModel::class);
$category_type = 'asset';
return view('models/edit')->with('category_type',$category_type)
->with('depreciation_list', Helper::depreciationList())
@@ -69,6 +71,7 @@ class AssetModelsController extends Controller
public function store(ImageUploadRequest $request)
{
$this->authorize('create', AssetModel::class);
// Create a new asset model
$model = new AssetModel;
@@ -124,7 +127,8 @@ class AssetModelsController extends Controller
*/
public function apiStore(Request $request)
{
//COPYPASTA!!!! FIXME
//COPYPASTA!!!! FIXME
$this->authorize('create', AssetModel::class);
$model = new AssetModel;
$settings=Input::all();
@@ -162,6 +166,7 @@ class AssetModelsController extends Controller
*/
public function edit($modelId = null)
{
$this->authorize('update', AssetModel::class);
if ($item = AssetModel::find($modelId)) {
$category_type = 'asset';
$view = View::make('models/edit', compact('item','category_type'));
@@ -185,6 +190,7 @@ class AssetModelsController extends Controller
*/
public function update(ImageUploadRequest $request, $modelId = null)
{
$this->authorize('update', AssetModel::class);
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
// Redirect to the models management page
@@ -255,6 +261,7 @@ class AssetModelsController extends Controller
*/
public function destroy($modelId)
{
$this->authorize('delete', AssetModel::class);
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
return redirect()->route('models.index')->with('error', trans('admin/models/message.not_found'));
@@ -291,7 +298,7 @@ class AssetModelsController extends Controller
*/
public function getRestore($modelId = null)
{
$this->authorize('create', AssetModel::class);
// Get user information
$model = AssetModel::withTrashed()->find($modelId);
@@ -322,6 +329,7 @@ class AssetModelsController extends Controller
*/
public function show($modelId = null)
{
$this->authorize('view', AssetModel::class);
$model = AssetModel::withTrashed()->find($modelId);
if (isset($model->id)) {
@@ -393,20 +401,39 @@ class AssetModelsController extends Controller
$models_raw_array = Input::get('ids');
if (is_array($models_raw_array)) {
$models = AssetModel::whereIn('id', $models_raw_array)->get();
$nochange = ['NC' => 'No Change'];
$fieldset_list = $nochange + Helper::customFieldsetList();
$depreciation_list = $nochange + Helper::depreciationList();
$category_list = $nochange + Helper::categoryList('asset');
$manufacturer_list = $nochange + Helper::manufacturerList();
// Make sure some IDs have been selected
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();
// If deleting....
if ($request->input('bulk_actions')=='delete') {
$valid_count = 0;
foreach ($models as $model) {
if ($model->assets_count == 0) {
$valid_count++;
}
}
return view('models/bulk-delete', compact('models'))->with('valid_count', $valid_count);
// Otherwise display the bulk edit screen
} else {
$nochange = ['NC' => 'No Change'];
$fieldset_list = $nochange + Helper::customFieldsetList();
$depreciation_list = $nochange + Helper::depreciationList();
$category_list = $nochange + Helper::categoryList('asset');
$manufacturer_list = $nochange + Helper::manufacturerList();
return view('models/bulk-edit', compact('models'))
->with('manufacturer_list', $manufacturer_list)
->with('category_list', $category_list)
->with('fieldset_list', $fieldset_list)
->with('depreciation_list', $depreciation_list);
}
return view('models/bulk-edit', compact('models'))
->with('manufacturer_list', $manufacturer_list)
->with('category_list', $category_list)
->with('fieldset_list', $fieldset_list)
->with('depreciation_list', $depreciation_list);
}
return redirect()->route('models.index')
@@ -429,6 +456,7 @@ class AssetModelsController extends Controller
$models_raw_array = Input::get('ids');
$update_array = array();
if (($request->has('manufacturer_id') && ($request->input('manufacturer_id')!='NC'))) {
$update_array['manufacturer_id'] = $request->input('manufacturer_id');
}
@@ -455,4 +483,52 @@ class AssetModelsController extends Controller
}
/**
* Validate and delete the given Asset Models. An Asset Model
* cannot be deleted if there are associated assets.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
*/
public function postBulkDelete(Request $request)
{
$models_raw_array = Input::get('ids');
if ((is_array($models_raw_array)) && (count($models_raw_array) > 0)) {
$models = AssetModel::whereIn('id', $models_raw_array)->withCount('assets')->get();
$del_error_count = 0;
$del_count = 0;
foreach ($models as $model) {
\Log::debug($model->id);
if ($model->assets_count > 0) {
$del_error_count++;
} else {
$model->delete();
$del_count++;
}
}
\Log::debug($del_count);
\Log::debug($del_error_count);
if ($del_error_count == 0) {
return redirect()->route('models.index')
->with('success', trans('admin/models/message.bulkdelete.success',['success_count'=> $del_count] ));
}
return redirect()->route('models.index')
->with('warning', trans('admin/models/message.bulkdelete.success_partial', ['fail_count'=>$del_error_count, 'success_count'=> $del_count]));
}
return redirect()->route('models.index')
->with('error', trans('admin/models/message.bulkdelete.error'));
}
}
+44 -9
View File
@@ -219,7 +219,7 @@ class AssetsController extends Controller
// Was the asset created?
if ($asset->save()) {
$asset->logCreate();
if (request('assigned_user')) {
$target = User::find(request('assigned_user'));
@@ -402,13 +402,6 @@ class AssetsController extends Controller
$asset->delete();
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->user_id = Auth::user()->id;
$logaction->logaction('deleted');
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
}
@@ -467,8 +460,14 @@ class AssetsController extends Controller
$asset->location_id = ($target) ? $target->id : '';
} elseif (request('checkout_to_type')=='asset') {
if (request('assigned_asset') == $assetId) {
return redirect()->back()->with('error', 'You cannot check an asset out to itself.');
}
$target = Asset::where('id','!=',$assetId)->find(request('assigned_asset'));
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
if ($target->location_id!='') {
$asset->location_id = ($target) ? $target->location_id : '';
@@ -582,6 +581,7 @@ class AssetsController extends Controller
$data['log_id'] = $logaction->id;
$data['first_name'] = get_class($target) == User::class ? $target->first_name : '';
$data['last_name'] = get_class($target) == User::class ? $target->last_name : '';
$data['item_name'] = $asset->present()->name();
$data['checkin_date'] = $logaction->created_at;
$data['item_tag'] = $asset->asset_tag;
@@ -919,6 +919,14 @@ class AssetsController extends Controller
if (isset($asset->id)) {
// Restore the asset
Asset::withTrashed()->where('id', $assetId)->restore();
$logaction = new Actionlog();
$logaction->item_type = Asset::class;
$logaction->item_id = $asset->id;
$logaction->created_at = date("Y-m-d H:i:s");
$logaction->user_id = Auth::user()->id;
$logaction->logaction('restored');
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
@@ -1087,7 +1095,7 @@ class AssetsController extends Controller
\Log::debug($request->input('ids'));
if (($request->has('ids')) && (count($request->input('ids') > 0))) {
if (($request->has('ids')) && (count($request->input('ids')) > 0)) {
$assets = $request->input('ids');
if (($request->has('purchase_date'))
|| ($request->has('purchase_cost'))
@@ -1128,9 +1136,17 @@ class AssetsController extends Controller
if ($request->has('warranty_months')) {
$update_array['warranty_months'] = $request->input('warranty_months');
}
if ($request->has('rtd_location_id')) {
$update_array['rtd_location_id'] = $request->input('rtd_location_id');
if (($request->has('update_real_loc'))
&& (($request->input('update_real_loc')) == '1'))
{
$update_array['location_id'] = $request->input('rtd_location_id');
}
}
if ($request->has('status_id')) {
$update_array['status_id'] = $request->input('status_id');
}
@@ -1197,9 +1213,14 @@ class AssetsController extends Controller
$user = User::find(e(Input::get('assigned_to')));
$admin = Auth::user();
if (!$user) {
return redirect()->route('hardware/bulkcheckout')->withInput()->with('error', trans('admin/hardware/message.checkout.user_does_not_exist'));
}
if (!is_array(Input::get('selected_assets'))) {
return redirect()->route('hardware/bulkcheckout')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
}
$asset_ids = array_filter(Input::get('selected_assets'));
if ((Input::has('checkout_at')) && (Input::get('checkout_at')!= date("Y-m-d"))) {
@@ -1214,6 +1235,7 @@ class AssetsController extends Controller
$expected_checkin = '';
}
$errors = [];
DB::transaction(function () use ($user, $admin, $checkout_at, $expected_checkin, $errors, $asset_ids) {
@@ -1222,6 +1244,14 @@ class AssetsController extends Controller
$this->authorize('checkout', $asset);
$error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, e(Input::get('note')), null);
if ($user->location_id!='') {
$asset->location_id = $user->location_id;
$asset->unsetEventDispatcher();
$asset->save();
}
if ($error) {
array_merge_recursive($errors, $asset->getErrors()->toArray());
}
@@ -1255,6 +1285,7 @@ class AssetsController extends Controller
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
public function auditStore(Request $request, $id)
{
$this->authorize('audit', Asset::class);
@@ -1270,7 +1301,11 @@ class AssetsController extends Controller
}
$asset = Asset::findOrFail($id);
// We don't want to log this as a normal update, so let's bypass that
$asset->unsetEventDispatcher();
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d h:i:s');
if ($asset->save()) {
$asset->logAudit(request('note'), request('location_id'));
+35 -4
View File
@@ -50,17 +50,36 @@ class LoginController extends Controller
\Session::put('backUrl', \URL::previous());
}
function showLoginForm()
function showLoginForm(Request $request)
{
$this->loginViaRemoteUser($request);
if (Auth::check()) {
return redirect()->intended('dashboard');
}
if (Setting::getSettings()->login_common_disabled == "1") {
return view('errors.403');
}
return view('auth.login');
}
private function loginViaRemoteUser(Request $request)
{
$remote_user = $request->server('REMOTE_USER');
if (Setting::getSettings()->login_remote_user_enabled == "1" && isset($remote_user) && !empty($remote_user)) {
LOG::debug("Authenticatiing via REMOTE_USER.");
try {
$user = User::where('username', '=', $remote_user)->whereNull('deleted_at')->first();
LOG::debug("Remote user auth lookup complete");
if(!is_null($user)) Auth::login($user, true);
} catch(Exception $e) {
LOG::error("There was an error authenticating the Remote user: " . $e->getMessage());
}
}
}
private function login_via_ldap(Request $request)
private function loginViaLdap(Request $request)
{
LOG::debug("Binding user to LDAP.");
$ldap_user = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password'));
@@ -114,6 +133,10 @@ class LoginController extends Controller
*/
public function login(Request $request)
{
if (Setting::getSettings()->login_common_disabled == "1") {
return view('errors.403');
}
$validator = $this->validator(Input::all());
if ($validator->fails()) {
@@ -134,7 +157,7 @@ class LoginController extends Controller
if (Setting::getSettings()->ldap_enabled=='1') {
LOG::debug("LDAP is enabled.");
try {
$user = $this->login_via_ldap($request);
$user = $this->loginViaLdap($request);
Auth::login($user, true);
// If the user was unable to login via LDAP, log the error and let them fall through to
@@ -252,7 +275,15 @@ class LoginController extends Controller
public function logout(Request $request)
{
$request->session()->forget('2fa_authed');
Auth::logout();
$settings = Setting::getSettings();
$customLogoutUrl = $settings->login_remote_user_custom_logout_url ;
if ($settings->login_remote_user_enabled == '1' && $customLogoutUrl != '') {
return redirect()->away($customLogoutUrl);
}
return redirect()->route('login')->with('success', 'You have successfully logged out!');
}
@@ -12,4 +12,12 @@ class RegisterController extends Controller
{
$this->middleware('guest');
}
public function showRegistrationForm() {
abort(404,'Page not found');
}
public function register() {
abort(404,'Page not found');
}
}
@@ -40,6 +40,7 @@ class CategoriesController extends Controller
public function index()
{
// Show the page
$this->authorize('view', Category::class);
return view('categories/index');
}
@@ -55,6 +56,7 @@ class CategoriesController extends Controller
public function create()
{
// Show the page
$this->authorize('create', Category::class);
$category_types= Helper::categoryTypeList();
return view('categories/edit')->with('item', new Category)
->with('category_types', $category_types);
@@ -71,6 +73,7 @@ class CategoriesController extends Controller
*/
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Category::class);
$category = new Category();
$category->name = $request->input('name');
$category->category_type = $request->input('category_type');
@@ -110,6 +113,7 @@ class CategoriesController extends Controller
*/
public function edit($categoryId = null)
{
$this->authorize('edit', Category::class);
if (is_null($item = Category::find($categoryId))) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
}
@@ -132,7 +136,7 @@ class CategoriesController extends Controller
*/
public function update(ImageUploadRequest $request, $categoryId = null)
{
// Check if the blog post exists
$this->authorize('edit', Category::class);
if (is_null($category = Category::find($categoryId))) {
// Redirect to the categories management page
return redirect()->to('admin/categories')->with('error', trans('admin/categories/message.does_not_exist'));
@@ -198,6 +202,7 @@ class CategoriesController extends Controller
*/
public function destroy($categoryId)
{
$this->authorize('delete', Category::class);
// Check if the category exists
if (is_null($category = Category::find($categoryId))) {
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
@@ -231,6 +236,7 @@ class CategoriesController extends Controller
*/
public function show($id)
{
$this->authorize('view', Category::class);
if ($category = Category::find($id)) {
if ($category->category_type=='asset') {
@@ -194,7 +194,7 @@ class ComponentsController extends Controller
public function destroy($componentId)
{
if (is_null($component = Component::find($componentId))) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found'));
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
}
$this->authorize('delete', $component);
@@ -335,7 +335,7 @@ class ComponentsController extends Controller
return redirect()->route('components.index')->with('error',
trans('admin/components/message.not_found'));
}
$this->authorize('checkin', $component_assets);
$this->authorize('checkin', $component);
return view('components/checkin', compact('component_assets','component','asset'));
}
@@ -144,7 +144,7 @@ class DepartmentsController extends Controller
return view('departments/edit', compact('item'));
}
public function update(Request $request, $id) {
public function update(ImageUploadRequest $request, $id) {
$this->authorize('create', Department::class);
if (is_null($department = Department::find($id))) {
+3 -3
View File
@@ -47,7 +47,7 @@ class GroupsController extends Controller
$group = new Group;
// Get all the available permissions
$permissions = config('permissions');
$groupPermissions = array();
$groupPermissions = Helper::selectedPermissionsArray($permissions, $permissions);
$selectedPermissions = Input::old('permissions', $groupPermissions);
// Show the page
@@ -84,7 +84,7 @@ class GroupsController extends Controller
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
*/
public function edit($id = null)
public function edit($id)
{
$group = Group::find($id);
@@ -95,7 +95,7 @@ class GroupsController extends Controller
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found'));
}
/**
@@ -5,6 +5,8 @@ namespace App\Http\Controllers;
use App\Http\Transformers\ImportsTransformer;
use App\Models\Import;
use Illuminate\Http\Request;
use App\Models\Asset;
class ImportsController extends Controller
{
+11 -5
View File
@@ -288,7 +288,7 @@ class LicensesController extends Controller
}
$this->authorize('checkout', $licenseSeat);
$this->authorize('checkout', $license);
// Declare the rules for the form validation
$rules = [
@@ -315,7 +315,7 @@ class LicensesController extends Controller
$licenseSeat->asset_id = $request->input('asset_id');
// Override asset's assigned user if available
if ($target->assigned_to!='') {
if ($target->checkedOutToUser()) {
$licenseSeat->assigned_to = $target->assigned_to;
}
@@ -362,7 +362,14 @@ class LicensesController extends Controller
// Redirect to the asset management page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}
$this->authorize('checkin', $licenseSeat);
if (is_null($license = License::find($licenseSeat->license_id))) {
// Redirect to the asset management page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}
$this->authorize('checkout', $license);
return view('licenses/checkin', compact('licenseSeat'))->with('backto', $backTo);
}
@@ -386,8 +393,7 @@ class LicensesController extends Controller
}
$license = License::find($licenseSeat->license_id);
$this->authorize('checkin', $licenseSeat);
$this->authorize('checkout', $license);
if (!$license->reassignable) {
// Not allowed to checkin
@@ -40,6 +40,7 @@ class LocationsController extends Controller
public function index()
{
// Grab all the locations
$this->authorize('view', Location::class);
$locations = Location::orderBy('created_at', 'DESC')->with('parent', 'assets', 'assignedassets')->get();
// Show the page
@@ -57,6 +58,7 @@ class LocationsController extends Controller
*/
public function create()
{
$this->authorize('create', Location::class);
$locations = Location::orderBy('name', 'ASC')->get();
$location_options_array = Location::getLocationHierarchy($locations);
@@ -80,6 +82,7 @@ class LocationsController extends Controller
*/
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Location::class);
$location = new Location();
$location->name = $request->input('name');
$location->parent_id = $request->input('parent_id', null);
@@ -122,6 +125,7 @@ class LocationsController extends Controller
*/
public function apiStore(Request $request)
{
$this->authorize('create', Location::class);
$new['currency']=Setting::first()->default_currency;
// create a new location instance
@@ -158,6 +162,7 @@ class LocationsController extends Controller
*/
public function edit($locationId = null)
{
$this->authorize('edit', Location::class);
// Check if the location exists
if (is_null($item = Location::find($locationId))) {
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
@@ -186,6 +191,7 @@ class LocationsController extends Controller
*/
public function update(ImageUploadRequest $request, $locationId = null)
{
$this->authorize('edit', Location::class);
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
@@ -252,6 +258,7 @@ class LocationsController extends Controller
*/
public function destroy($locationId)
{
$this->authorize('delete', Location::class);
if (is_null($location = Location::find($locationId))) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.not_found'));
}
@@ -35,6 +35,7 @@ class ManufacturersController extends Controller
*/
public function index()
{
$this->authorize('index', Manufacturer::class);
return view('manufacturers/index', compact('manufacturers'));
}
@@ -49,6 +50,7 @@ class ManufacturersController extends Controller
*/
public function create()
{
$this->authorize('create', Manufacturer::class);
return view('manufacturers/edit')->with('item', new Manufacturer);
}
@@ -65,6 +67,7 @@ class ManufacturersController extends Controller
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Manufacturer::class);
$manufacturer = new Manufacturer;
$manufacturer->name = $request->input('name');
$manufacturer->user_id = Auth::user()->id;
@@ -104,6 +107,7 @@ class ManufacturersController extends Controller
*/
public function edit($id = null)
{
$this->authorize('edit', Manufacturer::class);
// Check if the manufacturer exists
if (is_null($item = Manufacturer::find($id))) {
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist'));
@@ -123,8 +127,9 @@ class ManufacturersController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @since [v1.0]
*/
public function update(Request $request, $manufacturerId = null)
public function update(ImageUploadRequest $request, $manufacturerId = null)
{
$this->authorize('edit', Manufacturer::class);
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturer page
@@ -186,6 +191,7 @@ class ManufacturersController extends Controller
*/
public function destroy($manufacturerId)
{
$this->authorize('delete', Manufacturer::class);
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturers page
@@ -224,6 +230,7 @@ class ManufacturersController extends Controller
*/
public function show($manufacturerId = null)
{
$this->authorize('view', Manufacturer::class);
$manufacturer = Manufacturer::find($manufacturerId);
if (isset($manufacturer->id)) {
@@ -235,6 +242,32 @@ class ManufacturersController extends Controller
return redirect()->route('manufacturers.index')->with('error', $error);
}
/**
* Restore a given Manufacturer (mark as un-deleted)
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.1.15]
* @param int $manufacturers_id
* @return Redirect
*/
public function restore($manufacturers_id)
{
$this->authorize('create', Manufacturer::class);
$manufacturer = Manufacturer::onlyTrashed()->where('id',$manufacturers_id)->first();
if ($manufacturer) {
// Not sure why this is necessary - it shouldn't fail validation here, but it fails without this, so....
$manufacturer->setValidating(false);
if ($manufacturer->restore()) {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.restore.success'));
}
return redirect()->back()->with('error', 'Could not restore.');
}
return redirect()->back()->with('error', trans('admin/manufacturers/message.does_not_exist'));
}
+9
View File
@@ -29,4 +29,13 @@ class ModalController extends Controller
function user() {
return view('modals.user');
}
function category() {
return view('modals.category');
}
function manufacturer() {
return view('modals.manufacturer');
}
}
+2 -1
View File
@@ -11,6 +11,7 @@ use App\Models\Setting;
use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\ImageUploadRequest;
/**
* This controller handles all actions related to User Profiles for
@@ -40,7 +41,7 @@ class ProfileController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function postIndex()
public function postIndex(ImageUploadRequest $request)
{
$user = Auth::user();
+22 -8
View File
@@ -7,6 +7,7 @@ use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use App\Models\CustomField;
use App\Models\Depreciation;
use App\Models\License;
use App\Models\Setting;
use Carbon\Carbon;
@@ -221,11 +222,12 @@ class ReportsController extends Controller
public function getDeprecationReport()
{
$depreciations = Depreciation::get();
// Grab all the assets
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'assetlog', 'company', 'model.category', 'model.depreciation')
->orderBy('created_at', 'DESC')->get();
return view('reports/depreciation', compact('assets'));
return view('reports/depreciation', compact('assets'))->with('depreciations',$depreciations);
}
/**
@@ -473,7 +475,7 @@ class ReportsController extends Controller
$header[] = trans('admin/hardware/table.purchase_date');
}
if ($request->has('purchase_cost')) {
if (($request->has('purchase_cost')) || ($request->has('depreciation'))) {
$header[] = trans('admin/hardware/table.purchase_cost');
}
@@ -515,7 +517,6 @@ class ReportsController extends Controller
$header[] = 'Warranty Expires';
}
if ($request->has('depreciation')) {
$header[] = 'Purchase Cost';
$header[] = 'Value';
$header[] = 'Diff';
}
@@ -536,6 +537,14 @@ class ReportsController extends Controller
$header[] = trans('general.updated_at');
}
if ($request->has('last_audit_date')) {
$header[] = trans('general.last_audit');
}
if ($request->has('next_audit_date')) {
$header[] = trans('general.next_audit_date');
}
if ($request->has('notes')) {
$header[] = trans('general.notes');
}
@@ -617,7 +626,7 @@ class ReportsController extends Controller
}
if ($request->has('category')) {
$row[] = ($asset->model->category) ? $asset->model->category->name : '';
$row[] = (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '';
}
if ($request->has('manufacturer')) {
@@ -637,7 +646,7 @@ class ReportsController extends Controller
}
if ($request->has('eol')) {
$row[] = ($asset->eol) ? $asset->present()->eol_date() : '';
$row[] = ($asset->purchase_date!='') ? $asset->present()->eol_date() : '';
}
if ($request->has('order')) {
@@ -686,9 +695,6 @@ class ReportsController extends Controller
$row[] = $asset->present()->warrantee_expires();
}
if ($request->has('purchase_cost')) {
$row[] = ($asset->purchase_cost!='') ? Helper::formatCurrencyOutput($asset->purchase_cost) : '';
}
if ($request->has('depreciation')) {
$depreciation = $asset->getDepreciatedValue();
@@ -713,6 +719,14 @@ class ReportsController extends Controller
$row[] = ($asset->updated_at) ? $asset->updated_at : '';
}
if ($request->has('last_audit_date')) {
$row[] = ($asset->last_audit_date) ? $asset->last_audit_date : '';
}
if ($request->has('next_audit_date')) {
$row[] = ($asset->next_audit_date) ? $asset->next_audit_date : '';
}
if ($request->has('notes')) {
$row[] = ($asset->notes) ? $asset->notes : '';
}
+50 -18
View File
@@ -22,6 +22,7 @@ use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsLdapRequest;
use App\Helpers\Helper;
use App\Notifications\FirstAdminNotification;
/**
* This controller handles all actions related to Settings for
@@ -57,9 +58,10 @@ class SettingsController extends Controller
$protocol = array_key_exists('HTTPS', $_SERVER) && ( $_SERVER['HTTPS'] == "on") ? 'https://' : 'http://';
$host = $_SERVER['SERVER_NAME'];
if (($protocol === 'http://' && $_SERVER['SERVER_PORT'] != '80') || ($protocol === 'https://' && $_SERVER['SERVER_PORT'] != '443')) {
$host .= ':' . $_SERVER['SERVER_PORT'];
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (($protocol === 'http://' && $port != '80') || ($protocol === 'https://' && $port != '443')) {
$host .= ':' . $port;
}
$pageURL = $protocol . $host . $_SERVER['REQUEST_URI'];
@@ -67,7 +69,7 @@ class SettingsController extends Controller
$start_settings['url_config'] = url('/');
$start_settings['real_url'] = $pageURL;
// Curl the .env file to make sure it's not accessible via a browser
$ch = curl_init($protocol . $host.'/.env');
curl_setopt($ch, CURLOPT_HEADER, true); // we want headers
@@ -150,28 +152,31 @@ class SettingsController extends Controller
$user = new User;
$user->first_name = $data['first_name']= e(Input::get('first_name'));
$user->last_name = e(Input::get('last_name'));
$user->email = $data['email'] = e(Input::get('email'));
$user->first_name = $data['first_name']= $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->email = $data['email'] = $request->input('email');
$user->activated = 1;
$permissions = array('superuser' => 1);
$user->permissions = json_encode($permissions);
$user->username = $data['username'] = e(Input::get('username'));
$user->password = bcrypt(Input::get('password'));
$data['password'] = Input::get('password');
$user->username = $data['username'] = $request->input('username');
$user->password = bcrypt($request->input('password'));
$data['password'] = $request->input('password');
$settings = new Setting;
$settings->site_name = e(Input::get('site_name'));
$settings->alert_email = e(Input::get('email'));
$settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0);
$settings->site_name = $request->input('site_name');
$settings->alert_email = $request->input('email');
$settings->alerts_enabled = 1;
$settings->pwd_secure_min = 10;
$settings->brand = 1;
$settings->locale = 'en';
$settings->default_currency = 'USD';
$settings->locale = $request->input('locale', 'en');
$settings->default_currency = $request->input('default_currency', "USD");
$settings->user_id = 1;
$settings->email_domain = e(Input::get('email_domain'));
$settings->email_format = e(Input::get('email_format'));
$settings->email_domain = $request->input('email_domain');
$settings->email_format = $request->input('email_format');
$settings->next_auto_tag_base = 1;
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
if ((!$user->isValid()) || (!$settings->isValid())) {
@@ -182,11 +187,20 @@ class SettingsController extends Controller
$settings->save();
if (Input::get('email_creds')=='1') {
Mail::send(['text' => 'emails.firstadmin'], $data, function ($m) use ($data) {
$data = array();
$data['email'] = $user->email;
$data['username'] = $user->username;
$data['first_name'] = $user->first_name;
$data['last_name'] = $user->last_name;
$data['password'] = $user->password;
$user->notify(new FirstAdminNotification($data));
/*Mail::send(['text' => 'emails.firstadmin'], $data, function ($m) use ($data) {
$m->to($data['email'], $data['first_name']);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.your_credentials'));
});
});*/
}
@@ -311,8 +325,18 @@ class SettingsController extends Controller
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$setting->modellist_displays = '';
if (($request->has('show_in_model_list')) && (count($request->input('show_in_model_list')) > 0))
{
$setting->modellist_displays = implode(',', $request->input('show_in_model_list'));
}
$setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0');
$setting->load_remote = $request->input('load_remote', '0');
$setting->show_archived_in_list = $request->input('show_archived_in_list', '0');
$setting->dashboard_message = $request->input('dashboard_message');
$setting->email_domain = $request->input('email_domain');
$setting->email_format = $request->input('email_format');
$setting->username_format = $request->input('username_format');
@@ -370,6 +394,9 @@ class SettingsController extends Controller
$setting->brand = $request->input('brand', '1');
$setting->header_color = $request->input('header_color');
$setting->support_footer = $request->input('support_footer');
$setting->footer_text = $request->input('footer_text');
$setting->skin = $request->input('skin');
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0');
@@ -458,6 +485,11 @@ class SettingsController extends Controller
$setting->pwd_secure_min = (int) $request->input('pwd_secure_min');
$setting->pwd_secure_complexity = '';
# remote user login
$setting->login_remote_user_enabled = (int)$request->input('login_remote_user_enabled');
$setting->login_common_disabled= (int)$request->input('login_common_disabled');
$setting->login_remote_user_custom_logout_url = $request->input('login_remote_user_custom_logout_url');
if ($request->has('pwd_secure_complexity')) {
$setting->pwd_secure_complexity = implode('|', $request->input('pwd_secure_complexity'));
}
@@ -32,12 +32,13 @@ class StatuslabelsController extends Controller
public function index()
{
$this->authorize('view', Statuslabel::class);
return view('statuslabels.index', compact('statuslabels'));
}
public function show($id)
{
$this->authorize('view', Statuslabel::class);
if ($statuslabel = Statuslabel::find($id)) {
return view('statuslabels.view')->with('statuslabel', $statuslabel);
}
@@ -55,6 +56,7 @@ class StatuslabelsController extends Controller
public function create()
{
// Show the page
$this->authorize('create', Statuslabel::class);
$item = new Statuslabel;
$use_statuslabel_type = $item->getStatuslabelType();
$statuslabel_types = Helper::statusTypeList();
@@ -72,6 +74,7 @@ class StatuslabelsController extends Controller
public function store(Request $request)
{
$this->authorize('create', Statuslabel::class);
// create a new model instance
$statusLabel = new Statuslabel();
@@ -90,9 +93,9 @@ class StatuslabelsController extends Controller
$statusLabel->archived = $statusType['archived'];
$statusLabel->color = Input::get('color');
$statusLabel->show_in_nav = Input::get('show_in_nav', 0);
$statusLabel->default_label = Input::get('default_label', 0);
// Was the asset created?
if ($statusLabel->save()) {
// Redirect to the new Statuslabel page
return redirect()->route('statuslabels.index')->with('success', trans('admin/statuslabels/message.create.success'));
@@ -106,6 +109,7 @@ class StatuslabelsController extends Controller
*/
public function apiStore(Request $request)
{
$this->authorize('create', Statuslabel::class);
$statuslabel = new Statuslabel();
if (!$request->has('statuslabel_types')) {
return JsonResponse::create(["error" => trans('validation.statuslabel_type')], 500);
@@ -137,6 +141,7 @@ class StatuslabelsController extends Controller
*/
public function edit($statuslabelId = null)
{
$this->authorize('update', Statuslabel::class);
// Check if the Statuslabel exists
if (is_null($item = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
@@ -159,6 +164,7 @@ class StatuslabelsController extends Controller
*/
public function update(Request $request, $statuslabelId = null)
{
$this->authorize('update', Statuslabel::class);
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
@@ -179,6 +185,7 @@ class StatuslabelsController extends Controller
$statuslabel->archived = $statustype['archived'];
$statuslabel->color = Input::get('color');
$statuslabel->show_in_nav = Input::get('show_in_nav', 0);
$statuslabel->default_label = Input::get('default_label', 0);
// Was the asset created?
@@ -197,6 +204,7 @@ class StatuslabelsController extends Controller
*/
public function destroy($statuslabelId)
{
$this->authorize('delete', Statuslabel::class);
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.not_found'));
@@ -33,6 +33,7 @@ class SuppliersController extends Controller
public function index()
{
// Grab all the suppliers
$this->authorize('view', Supplier::class);
$suppliers = Supplier::orderBy('created_at', 'DESC')->get();
// Show the page
@@ -47,6 +48,7 @@ class SuppliersController extends Controller
*/
public function create()
{
$this->authorize('create', Supplier::class);
return view('suppliers/edit')->with('item', new Supplier);
}
@@ -59,6 +61,7 @@ class SuppliersController extends Controller
*/
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Supplier::class);
// Create a new supplier
$supplier = new Supplier;
// Save the location data
@@ -100,6 +103,7 @@ class SuppliersController extends Controller
*/
public function apiStore(Request $request)
{
$this->authorize('create', Supplier::class);
$supplier = new Supplier;
$supplier->name = $request->input('name');
$supplier->user_id = Auth::id();
@@ -118,6 +122,7 @@ class SuppliersController extends Controller
*/
public function edit($supplierId = null)
{
$this->authorize('edit', Supplier::class);
// Check if the supplier exists
if (is_null($item = Supplier::find($supplierId))) {
// Redirect to the supplier page
@@ -137,6 +142,7 @@ class SuppliersController extends Controller
*/
public function update($supplierId = null, ImageUploadRequest $request)
{
$this->authorize('edit', Supplier::class);
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
// Redirect to the supplier page
@@ -207,6 +213,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))) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.not_found'));
}
+45 -23
View File
@@ -34,6 +34,7 @@ use View;
use Illuminate\Http\Request;
use Gate;
use Artisan;
use App\Notifications\WelcomeNotification;
/**
* This controller handles all actions related to Users for
@@ -146,13 +147,16 @@ class UsersController extends Controller
$data['email'] = e($request->input('email'));
$data['username'] = e($request->input('username'));
$data['first_name'] = e($request->input('first_name'));
$data['last_name'] = e($request->input('last_name'));
$data['password'] = e($request->input('password'));
Mail::send('emails.send-login', $data, function ($m) use ($user) {
$user->notify(new WelcomeNotification($data));
/* Mail::send('emails.send-login', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.welcome', ['name' => $user->first_name]));
});
});*/
}
return redirect::route('users.index')->with('success', trans('admin/users/message.success.create'));
}
@@ -192,15 +196,18 @@ class UsersController extends Controller
// Send the credentials through email
$data = array();
$data['email'] = $request->input('email');
$data['username'] = $request->input('username');
$data['first_name'] = $request->input('first_name');
$data['last_name'] = $request->input('last_name');
$data['last_name'] = e($request->input('last_name'));
$data['password'] = $request->input('password');
Mail::send('emails.send-login', $data, function ($m) use ($user) {
$user->notify(new WelcomeNotification($data));
/*Mail::send('emails.send-login', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.welcome', ['name' => $user->first_name]));
});
});*/
}
return JsonResponse::create($user);
@@ -431,7 +438,7 @@ class UsersController extends Controller
public function postBulkEdit(Request $request)
{
$this->authorize('update', User::class);
if ((!Input::has('ids')) || (count(Input::has('ids')) == 0)) {
if ((!Input::has('ids')) || (count(Input::input('ids')) == 0)) {
return redirect()->back()->with('error', 'No users selected');
} else {
@@ -461,7 +468,7 @@ class UsersController extends Controller
public function postBulkEditSave(Request $request)
{
$this->authorize('update', User::class);
if ((!Input::has('ids')) || (count(Input::has('ids')) == 0)) {
if ((!Input::has('ids')) || (count(Input::input('ids')) == 0)) {
return redirect()->back()->with('error', 'No users selected');
} else {
@@ -480,6 +487,11 @@ class UsersController extends Controller
if ($request->has('company_id')) {
$update_array['company_id'] = $request->input('company_id');
}
if ($request->has('locale')) {
$update_array['locale'] = $request->input('locale');
}
if ($request->has('manager_id')) {
@@ -847,16 +859,21 @@ class UsersController extends Controller
// Send the credentials through email
if ($row[3] != '') {
$data = array();
$data['email'] = trim(e($row[4]));
$data['username'] = trim(e($row[2]));
$data['first_name'] = trim(e($row[0]));
$data['last_name'] = trim(e($row[1]));
$data['password'] = $pass;
if ($newuser['email']) {
Mail::send('emails.send-login', $data, function ($m) use ($newuser) {
$user = User::where('username', $row[2])->first();
$user->notify(new WelcomeNotification($data));
/*Mail::send('emails.send-login', $data, function ($m) use ($newuser) {
$m->to($newuser['email'], $newuser['first_name'] . ' ' . $newuser['last_name']);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.welcome', ['name' => $newuser['first_name']]));
});
});*/
}
}
}
@@ -1063,7 +1080,7 @@ class UsersController extends Controller
// Open output stream
$handle = fopen('php://output', 'w');
User::with('assets', 'accessories', 'consumables', 'licenses', 'manager', 'groups', 'userloc', 'company','throttle')->orderBy('created_at', 'DESC')->chunk(500, function($users) use($handle) {
User::with('assets', 'accessories', 'consumables', 'department', 'licenses', 'manager', 'groups', 'userloc', 'company','throttle')->orderBy('created_at', 'DESC')->chunk(500, function($users) use($handle) {
$headers=[
// strtolower to prevent Excel from trying to open it as a SYLK file
strtolower(trans('general.id')),
@@ -1075,6 +1092,7 @@ class UsersController extends Controller
trans('admin/users/table.email'),
trans('admin/users/table.manager'),
trans('admin/users/table.location'),
trans('general.department'),
trans('general.assets'),
trans('general.licenses'),
trans('general.accessories'),
@@ -1105,6 +1123,7 @@ class UsersController extends Controller
$user->email,
($user->manager) ? $user->manager->present()->fullName() : '',
($user->userloc) ? $user->userloc->name : '',
($user->department) ? $user->department->name : '',
$user->assets->count(),
$user->licenses->count(),
$user->accessories->count(),
@@ -1131,20 +1150,23 @@ class UsersController extends Controller
}
public function postTwoFactorReset(Request $request)
/**
* LDAP form processing.
*
* @author Aladin Alaily
* @since [v1.8]
* @return \Illuminate\Http\RedirectResponse
*/
public function printInventory($id)
{
if (Gate::denies('users.edit')) {
return response()->json(['message' => trans('general.insufficient_permissions')], 500);
}
try {
$user = User::find($request->get('id'));
$user->two_factor_secret = null;
$user->two_factor_enrolled = 0;
$user->save();
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
} catch (\Exception $e) {
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_error')], 500);
}
$show_user = User::where('id',$id)->withTrashed()->first();
$assets = Asset::where('assigned_to', $id)->where('assigned_type', User::class)->with('model', 'model.category')->get();
$licenses = $show_user->licenses()->get();
$accessories = $show_user->accessories()->get();
$consumables = $show_user->consumables()->get();
return view('users/print')->with('assets', $assets)->with('licenses',$licenses)->with('accessories', $accessories)->with('consumables', $consumables)->with('show_user', $show_user);
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ class CheckForSetup
} else {
if (!($request->is('setup*')) && !($request->is('.env'))) {
return redirect(url('/').'/setup')->with('Request', $request);
return redirect(url('/').'/setup');
}
return $next($request);
+4 -1
View File
@@ -36,13 +36,16 @@ class AssetRequest extends Request
'checkin_date' => 'date',
'supplier_id' => 'integer|nullable',
'status' => 'integer|nullable',
'asset_tag' => 'required',
'purchase_cost' => 'numeric|nullable',
"assigned_user" => 'sometimes:required_without_all:assigned_asset,assigned_location',
"assigned_asset" => 'sometimes:required_without_all:assigned_user,assigned_location',
"assigned_location" => 'sometimes:required_without_all:assigned_user,assigned_asset',
];
$settings = \App\Models\Setting::getSettings();
$rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required';
$model = AssetModel::find($this->request->get('model_id'));
if (($model) && ($model->fieldset)) {
+2 -1
View File
@@ -24,7 +24,8 @@ class ImageUploadRequest extends Request
public function rules()
{
return [
'image' => 'mimes:png,gif,jpg,jpeg,svg|max:2000'
'image' => 'mimes:png,gif,jpg,jpeg,svg|max:2000',
'avatar' => 'mimes:png,gif,jpg,jpeg,svg|max:2000',
];
}
+1 -1
View File
@@ -26,7 +26,7 @@ class ItemImportRequest extends FormRequest
public function rules()
{
return [
//
'import-type' => 'required',
];
}
@@ -32,7 +32,7 @@ class AccessoriesTransformer
'notes' => ($accessory->notes) ? e($accessory->notes) : null,
'qty' => ($accessory->qty) ? (int) $accessory->qty : null,
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,
'purchase_cost' => ($accessory->purchase_cost) ? e($accessory->purchase_cost) : null,
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => $accessory->numRemaining(),
@@ -37,7 +37,7 @@ class ActionlogsTransformer
] : null,
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(), 'date'): null,
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date'): null,
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
'action_type' => $actionlog->present()->actionType(),
'admin' => ($actionlog->user) ? [
@@ -54,6 +54,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,
];
@@ -22,8 +22,18 @@ class AssetMaintenancesTransformer
{
$array = [
'id' => (int) $assetmaintenance->id,
'asset_name' => ($assetmaintenance->asset) ? ['id' => $assetmaintenance->asset->id,'name'=> e($assetmaintenance->asset->name)] : null,
'asset' => ($assetmaintenance->asset) ? [
'id' => (int) $assetmaintenance->asset->id,
'name'=> ($assetmaintenance->asset->name) ? e($assetmaintenance->asset->name) : null,
'asset_tag'=> e($assetmaintenance->asset->asset_tag)
] : null,
'title' => ($assetmaintenance->title) ? e($assetmaintenance->title) : null,
'location' => (($assetmaintenance->asset) && ($assetmaintenance->asset->location)) ? [
'id' => (int) $assetmaintenance->asset->location->id,
'name'=> e($assetmaintenance->asset->location->name),
] : null,
'notes' => ($assetmaintenance->notes) ? e($assetmaintenance->notes) : null,
'supplier' => ($assetmaintenance->supplier) ? ['id' => $assetmaintenance->supplier->id,'name'=> e($assetmaintenance->supplier->name)] : null,
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
@@ -34,7 +34,7 @@ class AssetModelsTransformer
'id' => (int) $assetmodel->depreciation->id,
'name'=> e($assetmodel->depreciation->name)
] : null,
'assets_count' => $assetmodel->assets_count,
'assets_count' => (int) $assetmodel->assets_count,
'category' => ($assetmodel->category) ? [
'id' => (int) $assetmodel->category->id,
'name'=> e($assetmodel->category->name)
@@ -53,7 +53,7 @@ class AssetModelsTransformer
$permissions_array['available_actions'] = [
'update' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', AssetModel::class) && ($assetmodel->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', AssetModel::class) && ($assetmodel->assets_count==0) && ($assetmodel->deleted_at=='')) ? true : false,
'clone' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at=='')) ,
'restore' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at!='')) ? true : false,
];
+9 -5
View File
@@ -31,16 +31,18 @@ class AssetsTransformer
'name'=> e($asset->model->name)
] : null,
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => ($asset->purchase_date!='') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null ,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->present()->statusText),
'status_meta' => e($asset->present()->statusMeta),
'name'=> e($asset->assetstatus->name),
'status_type'=> e($asset->assetstatus->getStatuslabelType()),
'status_meta' => e($asset->present()->statusMeta),
] : null,
'category' => ($asset->model->category) ? [
'category' => (($asset->model) && ($asset->model->category)) ? [
'id' => (int) $asset->model->category->id,
'name'=> e($asset->model->category->name)
] : null,
'manufacturer' => ($asset->model->manufacturer) ? [
'manufacturer' => (($asset->model) && ($asset->model->manufacturer)) ? [
'id' => (int) $asset->model->manufacturer->id,
'name'=> e($asset->model->manufacturer->name)
] : null,
@@ -68,6 +70,8 @@ class AssetsTransformer
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($asset->updated_at, 'datetime'),
'last_audit_date' => Helper::getFormattedDateObject($asset->last_audit_date, 'datetime'),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date, 'date'),
'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'),
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
@@ -77,7 +81,7 @@ class AssetsTransformer
];
if (($asset->model->fieldset) && (count($asset->model->fieldset->fields)> 0)) {
if (($asset->model) && ($asset->model->fieldset) && (count($asset->model->fieldset->fields)> 0)) {
$fields_array = array();
foreach ($asset->model->fieldset->fields as $field) {
@@ -38,7 +38,7 @@ class CompaniesTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Company::class) ? true : false,
'delete' => Gate::allows('delete', Company::class) ? true : false,
'delete' => (Gate::allows('delete', Company::class) && ($company->assets_count == 0) && ($company->accessories_count == 0) && ($company->consumables_count == 0) && ($company->components_count == 0) && ($company->users_count == 0)) ? true : false,
];
$array += $permissions_array;
@@ -23,7 +23,7 @@ class ComponentsTransformer
'id' => (int) $component->id,
'name' => e($component->name),
'image' => ($component->image) ? e(url('/').'/uploads/components/'.e($component->image)) : null,
'serial_number' => ($component->serial) ? e($component->serial) : null,
'serial' => ($component->serial) ? e($component->serial) : null,
'location' => ($component->location) ? [
'id' => (int) $component->location->id,
'name' => e($component->location->name)
@@ -34,6 +34,10 @@ class ComponentsTransformer
'id' => (int) $component->category->id,
'name' => e($component->category->name)
] : null,
'location' => ($component->location) ? [
'id' => (int) $component->location->id,
'name' => e($component->location->name)
] : null,
'order_number' => e($component->order_number),
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost),
@@ -30,7 +30,7 @@ class ConsumablesTransformer
'location' => ($consumable->location) ? ['id' => (int) $consumable->location->id, 'name' => e($consumable->location->name)] : null,
'manufacturer' => ($consumable->manufacturer) ? ['id' => (int) $consumable->manufacturer->id, 'name' => e($consumable->manufacturer->name)] : null,
'min_amt' => (int) $consumable->min_amt,
'model_number' => e($consumable->model_number),
'model_number' => ($consumable->model_number!='') ? e($consumable->model_number) : null,
'remaining' => $consumable->numRemaining(),
'order_number' => e($consumable->order_number),
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
@@ -22,9 +22,11 @@ class CustomFieldsTransformer
{
$array = [
'id' => $field->id,
'name' => e($field->name),
'db_column_name' => e($field->db_column_name()),
'format' => e($field->format),
'field_values' => ($field->field_values) ? e($field->field_values) : null,
'required' => $field->pivot ? $field->pivot->required : false,
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
@@ -47,7 +47,7 @@ class DepartmentsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Department::class) ? true : false,
'delete' => Gate::allows('delete', Department::class) ? true : false,
'delete' => (Gate::allows('delete', Department::class) && ($department->users_count==0) && ($department->deleted_at=='')) ? true : false,
];
$array += $permissions_array;
@@ -0,0 +1,62 @@
<?php
namespace App\Http\Transformers;
use App\Models\LicenseSeat;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use App\Helpers\Helper;
class LicenseSeatsTransformer
{
public function transformLicenseSeats (Collection $seats, $total)
{
$array = array();
$seat_count = 0;
foreach ($seats as $seat) {
$seat_count++;
$array[] = self::transformLicenseSeat($seat, $seat_count);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformLicenseSeat (LicenseSeat $seat, $seat_count)
{
$array = [
'id' => (int) $seat->id,
'license_id' => (int) $seat->license->id,
'name' => 'Seat '.$seat_count,
'assigned_user' => ($seat->user) ? [
'id' => (int) $seat->user->id,
'name'=> e($seat->user->present()->fullName)
] : null,
'assigned_asset' => ($seat->asset) ? [
'id' => (int) $seat->asset->id,
'name'=> e($seat->asset->present()->fullName)
] : null,
'location' => ($seat->location()) ? [
'id' => (int) $seat->location()->id,
'name'=> e($seat->location()->name)
] : null,
'reassignable' => (bool) $seat->license->reassignable,
'user_can_checkout' => (($seat->assigned_to=='') && ($seat->asset_id=='')) ? true : false,
];
$permissions_array['available_actions'] = [
'checkout' => Gate::allows('checkout', License::class) ? true : false,
'checkin' => Gate::allows('checkin', License::class) ? true : false,
'clone' => Gate::allows('create', License::class) ? true : false,
'update' => Gate::allows('update', License::class) ? true : false,
'delete' => Gate::allows('delete', License::class) ? true : false,
];
$array += $permissions_array;
return $array;
}
}
@@ -25,7 +25,7 @@ class LicensesTransformer
'name' => e($license->name),
'company' => ($license->company) ? ['id' => (int) $license->company->id,'name'=> e($license->company->name)] : null,
'manufacturer' => ($license->manufacturer) ? ['id' => (int) $license->manufacturer->id,'name'=> e($license->manufacturer->name)] : null,
'product_key' => e($license->serial),
'product_key' => (Gate::allows('viewKeys', License::class)) ? e($license->serial) : '------------',
'order_number' => e($license->order_number),
'purchase_order' => e($license->purchase_order),
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
@@ -34,15 +34,16 @@ class LocationsTransformer
'id' => (int) $location->id,
'name' => e($location->name),
'image' => ($location->image) ? app('locations_upload_url').e($location->image) : null,
'address' => e($location->address),
'city' => e($location->city),
'state' => e($location->state),
'country' => e($location->country),
'zip' => e($location->zip),
'address' => ($location->address) ? e($location->address) : null,
'address2' => ($location->address2) ? e($location->address2) : null,
'city' => ($location->city) ? e($location->city) : null,
'state' => ($location->state) ? e($location->state) : null,
'country' => ($location->country) ? e($location->country) : null,
'zip' => ($location->zip) ? e($location->zip) : null,
'assigned_assets_count' => (int) $location->assigned_assets_count,
'assets_count' => (int) $location->assets_count,
'users_count' => (int) $location->users_count,
'currency' => ($location->currency) ? e($location->currency) : null,
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
'parent' => ($location->parent) ? [
@@ -57,7 +58,7 @@ class LocationsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => Gate::allows('delete', Location::class) ? true : false,
'delete' => (Gate::allows('delete', Location::class) && ($location->assigned_assets_count==0) && ($location->assets_count==0) && ($location->users_count==0) && ($location->deleted_at=='')) ? true : false,
];
$array += $permissions_array;
@@ -36,11 +36,13 @@ class ManufacturersTransformer
'accessories_count' => (int) $manufacturer->accessories_count,
'created_at' => Helper::getFormattedDateObject($manufacturer->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($manufacturer->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($manufacturer->deleted_at, 'datetime'),
];
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Manufacturer::class) ? true : false,
'delete' => Gate::allows('delete', Manufacturer::class) ? true : false,
'update' => (($manufacturer->deleted_at=='') && (Gate::allows('update', Manufacturer::class))) ? true : false,
'restore' => (($manufacturer->deleted_at!='') && (Gate::allows('create', Manufacturer::class))) ? true : false,
'delete' => (Gate::allows('delete', Manufacturer::class) && ($manufacturer->assets_count == 0) && ($manufacturer->licenses_count==0) && ($manufacturer->consumables_count==0) && ($manufacturer->accessories_count==0) && ($manufacturer->deleted_at=='')) ? true : false,
];
$array += $permissions_array;
@@ -26,6 +26,7 @@ class StatuslabelsTransformer
'type' => $statuslabel->getStatuslabelType(),
'color' => ($statuslabel->color) ? e($statuslabel->color) : null,
'show_in_nav' => ($statuslabel->show_in_nav=='1') ? true : false,
'default_label' => ($statuslabel->default_label =='1') ? true : false,
'assets_count' => (int) $statuslabel->assets_count,
'notes' => e($statuslabel->notes),
'created_at' => Helper::getFormattedDateObject($statuslabel->created_at, 'datetime'),
+2 -2
View File
@@ -25,8 +25,8 @@ class UsersTransformer
'id' => (int) $user->id,
'avatar' => e($user->present()->gravatar),
'name' => e($user->first_name).' '.($user->last_name),
'firstname' => e($user->first_name),
'lastname' => e($user->last_name),
'first_name' => e($user->first_name),
'last_name' => e($user->last_name),
'username' => e($user->username),
'employee_num' => e($user->employee_num),
'manager' => ($user->manager) ? [
+3
View File
@@ -41,6 +41,9 @@ class AccessoryImporter extends ItemImporter
$this->log("No Matching Accessory, Creating a new one");
$accessory = new Accessory();
$accessory->fill($this->sanitizeItemForStoring($accessory));
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
// $accessory->unsetEventDispatcher();
if ($accessory->save()) {
$accessory->logCreate('Imported using CSV Importer');
$this->log('Accessory ' . $this->item["name"] . ' was created');
+18 -3
View File
@@ -79,28 +79,43 @@ class AssetImporter extends ItemImporter
}
$this->item['asset_tag'] = $asset_tag;
// We need to save the user if it exists so that we can checkout to user later.
// Sanitizing the item will remove it.
if(array_key_exists('user', $this->item)) {
$user = $this->item['user'];
}
$item = $this->sanitizeItemForStoring($asset, $editingAsset);
// By default we're set this to location_id in the item.
// The location id fetched by the csv reader is actually the rtd_location_id.
// This will also set location_id, but then that will be overridden by the
// checkout method if necessary below.
if (isset($this->item["location_id"])) {
$item['rtd_location_id'] = $this->item['location_id'];
unset($item['location_id']);
}
if ($editingAsset) {
$asset->update($item);
} else {
$asset->fill($item);
}
// If we're updating, we don't want to overwrite old fields.
// If we're updating, we don't want to overwrite old fields.
if (array_key_exists('custom_fields', $this->item)) {
foreach ($this->item['custom_fields'] as $custom_field => $val) {
$asset->{$custom_field} = $val;
}
}
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
// $asset->unsetEventDispatcher();
if ($asset->save()) {
$asset->logCreate('Imported using csv importer');
$this->log('Asset ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created');
// If we have a user to checkout to, lets do so.
if(isset($user)) {
$asset->fresh()->checkOut($user);
}
return;
}
$this->logError($asset, 'Asset "' . $this->item['name'].'"');
+8 -8
View File
@@ -27,27 +27,27 @@ class ComponentImporter extends ItemImporter
public function createComponentIfNotExists()
{
$component = null;
$editingComponent = false;
$this->log("Creating Component");
$component = Component::where('name', $this->item['name']);
$component = Component::where('name', $this->item['name'])
->where('serial', $this->item['serial'])
->first();
if ($component) {
$editingComponent = true;
$this->log('A matching Component ' . $this->item["name"] . ' already exists. ');
$this->log('A matching Component ' . $this->item["name"] . ' with serial ' .$this->item['serial'].' already exists. ');
if (!$this->updating) {
$this->log("Skipping Component");
return;
}
$this->log("Updating Component");
$component = $this->components[$componentId];
$component->update($this->sanitizeItemFor($component));
$component->update($this->sanitizeItemForUpdating($component));
$component->save();
return;
}
$this->log("No matching component, creating one");
$component = new Component;
$component->fill($$this->sanitizeItemForStoring($component));
$component->fill($this->sanitizeItemForStoring($component));
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
$component->unsetEventDispatcher();
if ($component->save()) {
$component->logCreate('Imported using CSV Importer');
$this->log("Component " . $this->item["name"] . ' was created');
+2 -1
View File
@@ -40,7 +40,8 @@ class ConsumableImporter extends ItemImporter
$this->log("No matching consumable, creating one");
$consumable = new Consumable();
$consumable->fill($this->sanitizeItemForStoring($consumable));
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
$consumable->unsetEventDispatcher();
if ($consumable->save()) {
$consumable->logCreate('Imported using CSV Importer');
$this->log("Consumable " . $this->item["name"] . ' was created');
+14 -11
View File
@@ -55,7 +55,7 @@ abstract class Importer
'supplier' => 'supplier',
'termination_date' => 'termination date',
'warranty_months' => 'warranty',
'name' => 'name',
'full_name' => 'full name',
'email' => 'email',
'username' => 'username'
];
@@ -91,15 +91,14 @@ abstract class Importer
$this->fieldMap = $this->defaultFieldMap;
// By default the importer passes a url to the file.
// However, for testing we also support passing a string directly
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
if (is_file($file)) {
$this->csv = Reader::createFromPath($file);
} else {
$this->csv = Reader::createFromString($file);
}
$this->csv->setNewLine('\r\n');
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$this->tempPassword = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
}
// Cached Values for import lookups
@@ -153,7 +152,7 @@ abstract class Importer
$this->log("Custom Key: ${key}");
if (array_key_exists($key, $array)) {
$val = e(Encoding::toUTF8(trim($array[ $key ])));
$val = Encoding::toUTF8(trim($array[ $key ]));
}
// $this->log("${key}: ${val}");
return $val;
@@ -169,6 +168,7 @@ abstract class Importer
*/
public function lookupCustomKey($key)
{
// dd($this->fieldMap);
if (array_key_exists($key, $this->fieldMap)) {
$this->log("Found a match in our custom map: {$key} is " . $this->fieldMap[$key]);
return $this->fieldMap[$key];
@@ -200,7 +200,7 @@ abstract class Importer
public function array_smart_custom_field_fetch(array $array, $key)
{
$index_name = strtolower($key->name);
return array_key_exists($index_name, $array) ? e(trim($array[$index_name])) : false;
return array_key_exists($index_name, $array) ? trim($array[$index_name]) : false;
}
protected function log($string)
@@ -231,7 +231,7 @@ abstract class Importer
*/
protected function createOrFetchUser($row)
{
$user_name = $this->findCsvMatch($row, "name");
$user_name = $this->findCsvMatch($row, "full_name");
$user_email = $this->findCsvMatch($row, "email");
$user_username = $this->findCsvMatch($row, "username");
$first_name = '';
@@ -239,12 +239,15 @@ abstract class Importer
// A number was given instead of a name
if (is_numeric($user_name)) {
$this->log('User '.$user_name.' is not a name - assume this user already exists');
$user_username = '';
// No name was given
$user = User::find($user_name);
if($user) {
return $user;
}
$this->log('User with id'.$user_name.' does not exist. Continuing through our processes');
} elseif (empty($user_name)) {
$this->log('No user data provided - skipping user creation, just adding asset');
//$user_username = '';
return false;
} else {
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
$first_name = $user_email_array['first_name'];
+4 -4
View File
@@ -22,6 +22,9 @@ class ItemImporter extends Importer
protected function handle($row)
{
// Need to reset this between iterations or we'll have stale data.
$this->item = [];
$item_category = $this->findCsvMatch($row, "category");
if ($this->shouldUpdateField($item_category)) {
$this->item["category_id"] = $this->createOrFetchCategory($item_category);
@@ -67,10 +70,7 @@ class ItemImporter extends Importer
// NO need to call this method if we're running the user import.
// TODO: Merge these methods.
if(get_class($this) !== UserImporter::class) {
if ($this->item["user"] = $this->createOrFetchUser($row)) {
$this->item['assigned_to'] = $this->item['user']->id;
$this->item['assigned_type'] = User::class;
}
$this->item["user"] = $this->createOrFetchUser($row);
}
}
+2
View File
@@ -63,6 +63,8 @@ class LicenseImporter extends ItemImporter
} else {
$license->fill($this->sanitizeItemForStoring($license));
}
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
// $license->unsetEventDispatcher();
if ($license->save()) {
$license->logCreate('Imported using csv importer');
$this->log('License ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created');
+1 -1
View File
@@ -33,7 +33,7 @@ class UserImporter extends ItemImporter
$this->item['username'] = $this->findCsvMatch($row, 'username');
$this->item['first_name'] = $this->findCsvMatch($row, 'first_name');
$this->item['last_name'] = $this->findCsvMatch($row, 'last_name');
$this->item['email'] = $this->findCsvMatch($row, 'user_email');
$this->item['email'] = $this->findCsvMatch($row, 'email');
$this->item['phone'] = $this->findCsvMatch($row, 'phone_number');
$this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle');
$this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num');
+6 -6
View File
@@ -163,27 +163,27 @@ class Accessory extends SnipeModel
*/
public function scopeTextSearch($query, $search)
{
$search = explode('+', $search);
return $query->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('categories.name', 'LIKE', '%'.$search.'%');
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('manufacturer', function ($query) use ($search) {
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('location', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere('accessories.name', 'LIKE', '%'.$search.'%')
->orWhere('accessories.model_number', 'LIKE', '%'.$search.'%')
->orWhere('accessories.order_number', 'LIKE', '%'.$search.'%')
->orWhere('accessories.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('accessories.purchase_date', 'LIKE', '%'.$search.'%');
}
->orWhere('accessories.order_number', 'LIKE', '%'.$search.'%');
});
}
+2 -1
View File
@@ -218,7 +218,8 @@ class Actionlog extends SnipeModel
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere('action_type', 'LIKE', '%'.$search.'%')
->orWhere('note', 'LIKE', '%'.$search.'%');
->orWhere('note', 'LIKE', '%'.$search.'%')
->orWhere('log_meta', 'LIKE', '%'.$search.'%');
}
});
+35 -8
View File
@@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Log;
use Watson\Validating\ValidatingTrait;
use Illuminate\Notifications\Notifiable;
use DB;
/**
* Model for Assets.
@@ -49,7 +50,9 @@ class Asset extends Depreciable
'deleted_at',
'purchase_date',
'last_checkout',
'expected_checkin'
'expected_checkin',
'last_audit_date',
'next_audit_date'
];
@@ -68,6 +71,7 @@ class Asset extends Depreciable
'status' => 'integer',
'purchase_cost' => 'numeric|nullable',
'next_audit_date' => 'date|nullable',
'last_audit_date' => 'date|nullable',
];
/**
@@ -128,7 +132,11 @@ class Asset extends Depreciable
public function availableForCheckout()
{
if ((empty($this->assigned_to)) && (empty($this->deleted_at)) && ($this->assetstatus->deployable == 1)) {
if (
(empty($this->assigned_to)) &&
(empty($this->deleted_at)) &&
(($this->assetstatus) && ($this->assetstatus->deployable == 1)))
{
return true;
}
return false;
@@ -166,6 +174,10 @@ class Asset extends Depreciable
if ($location != null) {
$this->location_id = $location;
} else {
if($target->location) {
$this->location_id = $target->location->id;
}
}
if ($this->requireAcceptance()) {
@@ -211,7 +223,7 @@ class Asset extends Depreciable
*/
public function components()
{
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id')->withTrashed();
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty')->withTrashed();
}
/**
@@ -219,7 +231,9 @@ class Asset extends Depreciable
*/
public function get_depreciation()
{
return $this->model->depreciation;
if (($this->model) && ($this->model->depreciation)) {
return $this->model->depreciation;
}
}
/**
@@ -762,7 +776,7 @@ class Asset extends Depreciable
{
$search = explode(' OR ', $search);
return $query->leftJoin('users as assets_users',function ($leftJoin) {
return $query->leftJoin('users as assets_users',function ($leftJoin) {
$leftJoin->on("assets_users.id", "=", "assets.assigned_to")
->where("assets.assigned_type", "=", User::class);
})->leftJoin('locations as assets_locations',function ($leftJoin) {
@@ -798,7 +812,7 @@ class Asset extends Depreciable
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
$query->where('companies.name', 'LIKE', '%' . $search . '%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('defaultLoc', function ($query) use ($search) {
@@ -807,6 +821,7 @@ class Asset extends Depreciable
})->orWhere(function ($query) use ($search) {
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');
@@ -814,7 +829,6 @@ class Asset extends Depreciable
->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%')
->orWhere('assets.serial', 'LIKE', '%'.$search.'%')
->orWhere('assets.order_number', 'LIKE', '%'.$search.'%')
->orWhere('assets.purchase_date', 'LIKE', '%'.$search.'%')
->orWhere('assets.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('assets.notes', 'LIKE', '%'.$search.'%');
}
@@ -865,6 +879,7 @@ class Asset extends Depreciable
})->orWhere(function ($query) use ($search) {
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');
@@ -996,7 +1011,7 @@ class Asset extends Depreciable
}
if (($fieldname!='category') && ($fieldname!='location')
&& ($fieldname!='status_label') && ($fieldname!='model') && ($fieldname!='manufacturer')) {
&& ($fieldname!='status_label') && ($fieldname!='model') && ($fieldname!='company') && ($fieldname!='manufacturer')) {
$query->orWhere('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%');
}
@@ -1149,6 +1164,18 @@ class Asset extends Depreciable
return $query->leftJoin('locations as asset_locations', 'asset_locations.id', '=', 'assets.location_id')->orderBy('asset_locations.name', $order);
}
/**
* Query builder scope to order on default
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderRtdLocation($query, $order)
{
return $query->leftJoin('locations as rtd_asset_locations', 'rtd_asset_locations.id', '=', 'assets.rtd_location_id')->orderBy('rtd_asset_locations.name', $order);
}
/**
* Query builder scope to order on supplier name
+34 -6
View File
@@ -154,12 +154,12 @@ class AssetMaintenance extends Model implements ICompanyableChild
return $query->where(function ($query) use ($search) {
$query->where('title', 'LIKE', '%'.$search.'%')
->orWhere('notes', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenance_type', 'LIKE', '%'.$search.'%')
->orWhere('cost', 'LIKE', '%'.$search.'%')
->orWhere('start_date', 'LIKE', '%'.$search.'%')
->orWhere('completion_date', 'LIKE', '%'.$search.'%');
$query->where('asset_maintenances.title', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenances.notes', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenances.asset_maintenance_type', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenances.cost', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenances.start_date', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenances.completion_date', 'LIKE', '%'.$search.'%');
});
}
@@ -177,4 +177,32 @@ class AssetMaintenance extends Model implements ICompanyableChild
->orderBy('users.first_name', $order)
->orderBy('users.last_name', $order);
}
/**
* Query builder scope to order on asset tag
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderByTag($query, $order)
{
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
->orderBy('assets.asset_tag', $order);
}
/**
* Query builder scope to order on asset tag
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderByAssetName($query, $order)
{
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
->orderBy('assets.name', $order);
}
}
+12 -1
View File
@@ -55,7 +55,18 @@ class AssetModel extends SnipeModel
*
* @var array
*/
protected $fillable = ['name','manufacturer_id','category_id','eol', 'user_id', 'fieldset_id', 'model_number', 'notes'];
protected $fillable = [
'category_id',
'depreciation_id',
'eol',
'fieldset_id',
'image',
'manufacturer_id',
'model_number',
'name',
'notes',
'user_id',
];
public function assets()
{
+9 -1
View File
@@ -53,7 +53,15 @@ class Category extends SnipeModel
*
* @var array
*/
protected $fillable = ['name','category_type', 'user_id', 'use_default_eula','checkin_email','require_acceptance'];
protected $fillable = [
'category_type',
'checkin_email',
'eula_text',
'name',
'require_acceptance',
'use_default_eula',
'user_id',
];
public function has_models()
+11 -11
View File
@@ -55,7 +55,7 @@ final class Company extends SnipeModel
}
}
private static function scopeCompanyablesDirectly($query, $column = 'company_id')
private static function scopeCompanyablesDirectly($query, $column = 'company_id', $table_name = null )
{
if (Auth::user()) {
$company_id = Auth::user()->company_id;
@@ -63,7 +63,8 @@ final class Company extends SnipeModel
$company_id = null;
}
return $query->where($column, '=', $company_id);
$table = ($table_name) ? DB::getTablePrefix().$table_name."." : '';
return $query->where($table.$column, '=', $company_id);
}
public static function getIdFromInput($unescaped_input)
@@ -131,13 +132,13 @@ final class Company extends SnipeModel
}
}
public static function scopeCompanyables($query, $column = 'company_id')
public static function scopeCompanyables($query, $column = 'company_id', $table_name = null )
{
// If not logged in and hitting this, assume we are on the command line and don't scope?'
if (!static::isFullMultipleCompanySupportEnabled() || (Auth::check() && Auth::user()->isSuperUser()) || (!Auth::check())) {
return $query;
} else {
return static::scopeCompanyablesDirectly($query, $column);
return static::scopeCompanyablesDirectly($query, $column, $table_name);
}
}
@@ -149,7 +150,6 @@ final class Company extends SnipeModel
return $query;
} else {
$f = function ($q) {
static::scopeCompanyablesDirectly($q);
};
@@ -166,31 +166,31 @@ final class Company extends SnipeModel
public function users()
{
return $this->hasMany(User::class);
return $this->hasMany(User::class, 'company_id');
}
public function assets()
{
return $this->hasMany(Asset::class);
return $this->hasMany(Asset::class, 'company_id');
}
public function licenses()
{
return $this->hasMany(License::class);
return $this->hasMany(License::class, 'company_id');
}
public function accessories()
{
return $this->hasMany(Accessory::class);
return $this->hasMany(Accessory::class, 'company_id');
}
public function consumables()
{
return $this->hasMany(Consumable::class);
return $this->hasMany(Consumable::class, 'company_id');
}
public function components()
{
return $this->hasMany(Component::class);
return $this->hasMany(Component::class, 'company_id');
}
/**
+3 -2
View File
@@ -54,7 +54,9 @@ class Component extends SnipeModel
'purchase_cost',
'purchase_date',
'min_amt',
'order_number',
'qty',
'serial',
];
public function location()
@@ -143,8 +145,7 @@ class Component extends SnipeModel
})->orWhere('components.name', 'LIKE', '%'.$search.'%')
->orWhere('components.order_number', 'LIKE', '%'.$search.'%')
->orWhere('components.serial', 'LIKE', '%'.$search.'%')
->orWhere('components.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('components.purchase_date', 'LIKE', '%'.$search.'%');
->orWhere('components.purchase_cost', 'LIKE', '%'.$search.'%');
}
});
}
+3 -2
View File
@@ -50,10 +50,12 @@ class Consumable extends SnipeModel
protected $fillable = [
'category_id',
'company_id',
'item_no',
'location_id',
'manufacturer_id',
'name',
'order_number',
'model_number',
'purchase_cost',
'purchase_date',
'qty',
@@ -186,8 +188,7 @@ class Consumable extends SnipeModel
});
})->orWhere('consumables.name', 'LIKE', '%'.$search.'%')
->orWhere('consumables.order_number', 'LIKE', '%'.$search.'%')
->orWhere('consumables.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('consumables.purchase_date', 'LIKE', '%'.$search.'%');
->orWhere('consumables.purchase_cost', 'LIKE', '%'.$search.'%');
}
});
}
+36 -3
View File
@@ -8,6 +8,7 @@ use App\Http\Traits\UniqueUndeletedTrait;
use ForceUTF8\Encoding;
use EasySlugger\Utf8Slugger;
use Patchwork\Utf8;
use Illuminate\Validation\Rule;
class CustomField extends Model
{
@@ -29,8 +30,18 @@ class CustomField extends Model
"BOOLEAN" => "boolean",
];
public $rules = [
"name" => "required|unique:custom_fields"
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'element',
'format',
'field_values',
'field_encrypted',
'help_text'
];
// This is confusing, since it's actually the custom fields table that
@@ -160,7 +171,7 @@ class CustomField extends Model
public function getFormatAttribute($value)
{
foreach (self::$PredefinedFormats as $name => $pattern) {
if ($pattern === $value) {
if ($pattern === $value || $name === $value) {
return $name;
}
}
@@ -248,4 +259,26 @@ class CustomField extends Model
return substr($long_slug, 0, 50) . '_' . $id;
}
/**
* Get validation rules for custom fields to use with Validator
* @author [V. Cordes] [<volker@fdatek.de>]
* @param int $id
* @since [v4.1.10]
* @return Array
*/
public function validationRules()
{
return [
"name" => "required|unique:custom_fields",
"element" => [
"required",
Rule::in(['text', 'listbox'])
],
'format' => [
Rule::in(array_merge(array_keys(CustomField::$PredefinedFormats), CustomField::$PredefinedFormats))
],
'field_encrypted' => "nullable|boolean"
];
}
}
+26
View File
@@ -93,5 +93,31 @@ class Department extends SnipeModel
}
/**
* Query builder scope to order on location name
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderLocation($query, $order)
{
return $query->leftJoin('locations as department_location', 'departments.location_id', '=', 'department_location.id')->orderBy('department_location.name', $order);
}
/**
* Query builder scope to order on manager name
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderManager($query, $order)
{
return $query->leftJoin('users as department_user', 'departments.manager_id', '=', 'department_user.id')->orderBy('department_user.first_name', $order)->orderBy('department_user.last_name', $order);
}
}
+18 -19
View File
@@ -40,7 +40,6 @@ class License extends Depreciable
'seats' => 'required|min:1|max:1000000|integer',
'license_email' => 'email|nullable|max:120',
'license_name' => 'string|nullable|max:100',
'note' => 'string|nullable',
'notes' => 'string|nullable',
'company_id' => 'integer|nullable',
);
@@ -51,25 +50,25 @@ class License extends Depreciable
* @var array
*/
protected $fillable = [
'name',
'serial',
'purchase_date',
'purchase_cost',
'order_number',
'seats',
'notes',
'user_id',
'depreciation_id',
'license_name', //actually licensed_to
'license_email',
'supplier_id',
'expiration_date',
'purchase_order',
'termination_date',
'maintained',
'reassignable',
'company_id',
'manufacturer_id'
'depreciation_id',
'expiration_date',
'license_email',
'license_name', //actually licensed_to
'maintained',
'manufacturer_id',
'name',
'notes',
'order_number',
'purchase_cost',
'purchase_date',
'purchase_order',
'reassignable',
'seats',
'serial',
'supplier_id',
'termination_date',
'user_id',
];
public static function boot()
+13
View File
@@ -34,4 +34,17 @@ class LicenseSeat extends Model implements ICompanyableChild
{
return $this->belongsTo('\App\Models\Asset', 'asset_id')->withTrashed();
}
public function location()
{
if (($this->user) && ($this->user->location)) {
return $this->user->location;
} elseif (($this->asset) && ($this->asset->location)) {
return $this->asset->location;
}
return false;
}
}
+28 -2
View File
@@ -9,6 +9,7 @@ use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
use DB;
class Location extends SnipeModel
{
@@ -44,7 +45,19 @@ class Location extends SnipeModel
*
* @var array
*/
protected $fillable = ['name','parent_id','address','address2','city','state', 'country','zip','ldap_ou'];
protected $fillable = [
'name',
'parent_id',
'address',
'address2',
'city',
'state',
'country',
'zip',
'ldap_ou',
'currency',
'image',
];
protected $hidden = ['user_id'];
public function users()
@@ -184,7 +197,7 @@ class Location extends SnipeModel
})
// Ugly, ugly code because Laravel sucks at self-joins
->orWhere(function ($query) use ($search) {
$query->whereRaw("parent_id IN (select id from locations where name LIKE '%".$search."%') ");
$query->whereRaw("parent_id IN (select id from ".DB::getTablePrefix()."locations where name LIKE '%".$search."%') ");
});
});
@@ -204,4 +217,17 @@ class Location extends SnipeModel
// Left join here, or it will only return results with parents
return $query->leftJoin('locations as parent_loc', 'locations.parent_id', '=', 'parent_loc.id')->orderBy('parent_loc.name', $order);
}
/**
* Query builder scope to order on manager name
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderManager($query, $order)
{
return $query->leftJoin('users as location_user', 'locations.manager_id', '=', 'location_user.id')->orderBy('location_user.first_name', $order)->orderBy('location_user.last_name', $order);
}
}
+2 -2
View File
@@ -67,7 +67,7 @@ trait Loggable
];
if ($settings = Setting::getSettings()) {
$settings->notify(new CheckoutNotification($params));
// $settings->notify(new CheckoutNotification($params));
}
if (method_exists($target, 'notify')) {
@@ -182,7 +182,7 @@ trait Loggable
$log->location_id = null;
$log->note = $note;
$log->user_id = $user_id;
$log->logaction('created');
$log->logaction('create');
$log->save();
return $log;
}
+9 -4
View File
@@ -21,9 +21,7 @@ class Manufacturer extends SnipeModel
'support_email' => 'email|nullable'
);
protected $hidden = ['user_id','deleted_at'];
protected $hidden = ['user_id'];
/**
* Whether the model should inject it's identifier to the unique
@@ -40,7 +38,14 @@ class Manufacturer extends SnipeModel
*
* @var array
*/
protected $fillable = ['name','url','support_url','support_phone','support_email'];
protected $fillable = [
'name',
'image',
'support_email',
'support_phone',
'support_url',
'url',
];
+41 -17
View File
@@ -13,15 +13,15 @@ class Setting extends Model
use ValidatingTrait;
protected $rules = [
"brand" => 'required|min:1|numeric',
"qr_text" => 'max:31|nullable',
"logo_img" => 'mimes:jpeg,bmp,png,gif',
"alert_email" => 'email_array|nullable',
"default_currency" => 'required',
"locale" => 'required',
"slack_endpoint" => 'url|required_with:slack_channel|nullable',
"slack_channel" => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
"slack_botname" => 'string|nullable',
'brand' => 'required|min:1|numeric',
'qr_text' => 'max:31|nullable',
'logo_img' => 'mimes:jpeg,bmp,png,gif',
'alert_email' => 'email_array|nullable',
'default_currency' => 'required',
'locale' => 'required',
'slack_endpoint' => 'url|required_with:slack_channel|nullable',
'slack_channel' => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
'slack_botname' => 'string|nullable',
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
@@ -34,11 +34,14 @@ class Setting extends Model
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
"thumbnail_max_h" => 'numeric|max:500|min:25',
"pwd_secure_min" => "numeric|required|min:5",
"audit_warning_days" => "numeric|nullable",
"audit_interval" => "numeric|nullable",
"custom_forgot_pass_url" => "url|nullable",
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'thumbnail_max_h' => 'numeric|max:500|min:25',
'pwd_secure_min' => 'numeric|required|min:5',
'audit_warning_days' => 'numeric|nullable',
'audit_interval' => 'numeric|nullable',
'custom_forgot_pass_url' => 'url|nullable',
];
protected $fillable = ['site_name','email_domain','email_format','username_format'];
@@ -79,13 +82,27 @@ class Setting extends Model
public static function getDefaultEula()
{
$Parsedown = new \Parsedown();
if (Setting::getSettings()->default_eula_text) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
}
return null;
}
public function modellistCheckedValue ($element) {
// If the value is blank for some reason
if ($this->modellist_displays=='') {
return false;
}
$values = explode(',', $this->modellist_displays);
foreach ($values as $value) {
if ($value == $element) {
return true;
}
}
return false;
}
@@ -166,6 +183,13 @@ class Setting extends Model
return $this->slack_endpoint;
}
public function routeNotificationForMail()
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
return config('mail.reply_to.address');
}
public static function passwordComplexityRulesSaving($action = 'update')
{
$security_rules = '';
+7 -1
View File
@@ -27,7 +27,13 @@ class Statuslabel extends SnipeModel
'archived' => 'required',
);
protected $fillable = ['name', 'deployable', 'pending', 'archived'];
protected $fillable = [
'archived',
'deployable',
'name',
'notes',
'pending',
];
/**
+2 -2
View File
@@ -14,7 +14,7 @@ class Supplier extends SnipeModel
protected $table = 'suppliers';
protected $rules = array(
'name' => 'required|min:3|max:255|unique_undeleted',
'name' => 'required|min:1|max:255|unique_undeleted',
'address' => 'max:50|nullable',
'address2' => 'max:50|nullable',
'city' => 'max:255|nullable',
@@ -23,7 +23,7 @@ class Supplier extends SnipeModel
'fax' => 'min:7|max:35|nullable',
'phone' => 'min:7|max:35|nullable',
'contact' => 'max:100|nullable',
'notes' => 'max:255|nullable',
'notes' => 'max:191|nullable', // Default string length is 191 characters..
'email' => 'email|max:150|nullable',
'zip' => 'max:10|nullable',
'url' => 'sometimes|nullable|string|max:250',
+36 -38
View File
@@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use App\Http\Traits\UniqueUndeletedTrait;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use DB;
class User extends SnipeModel implements AuthenticatableContract, CanResetPasswordContract
{
@@ -27,21 +28,24 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
protected $table = 'users';
protected $injectUniqueIdentifier = true;
protected $fillable = [
'email',
'last_name',
'company_id',
'department_id',
'employee_num',
'jobtitle',
'location_id',
'password',
'phone_number',
'username',
'first_name',
'activated',
'address',
'city',
'state',
'company_id',
'country',
'department_id',
'email',
'employee_num',
'first_name',
'jobtitle',
'last_name',
'locale',
'location_id',
'manager_id',
'password',
'phone',
'state',
'username',
'zip',
];
@@ -327,44 +331,37 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
public static function generateFormattedNameFromFullName($format = 'filastname', $users_name)
{
$name = explode(" ", $users_name);
$name = str_replace("'", '', $name);
$first_name = $name[0];
$email_last_name = '';
$email_prefix = $first_name;
// If there is no last name given
if (!array_key_exists(1, $name)) {
$last_name='';
$email_last_name = $last_name;
$user_username = $first_name;
// If there was only one name given
if (strpos($users_name, ' ') === false) {
$first_name = $users_name;
$last_name = '';
$username = $users_name;
// There is a last name given
} else {
$last_name = str_replace($first_name . ' ', '', $users_name);
list($first_name, $last_name) = explode(" ", $users_name, 2);
if ($format=='filastname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name[0].$email_last_name;
// Assume filastname by default
$username = str_slug(substr($first_name, 0, 1).$last_name);
} elseif ($format=='firstname.lastname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name.'.'.$email_last_name;
if ($format=='firstname.lastname') {
$username = str_slug($first_name) . '.' . str_slug($last_name);
} elseif ($format=='lastnamefirstinitial') {
$username = str_slug($last_name.substr($first_name, 0, 1));
} elseif ($format=='firstname_lastname') {
$username = str_slug($first_name).'_'.str_slug($last_name);
} elseif ($format=='firstname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name;
$username = str_slug($first_name);
}
}
$user_username = $email_prefix;
$user['first_name'] = $first_name;
$user['last_name'] = $last_name;
$user['username'] = strtolower($user_username);
$user['username'] = strtolower($username);
return $user;
@@ -423,6 +420,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
->orWhere('users.phone', 'LIKE', "%$search%")
->orWhere('users.jobtitle', 'LIKE', "%$search%")
->orWhere('users.employee_num', 'LIKE', "%$search%")
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhere(function ($query) use ($search) {
$query->whereHas('userloc', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
@@ -441,7 +439,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
//Ugly, ugly code because Laravel sucks at self-joins
->orWhere(function ($query) use ($search) {
$query->whereRaw("users.manager_id IN (select id from users where first_name LIKE ? OR last_name LIKE ?)", ["%$search%", "%$search%"]);
$query->whereRaw(DB::getTablePrefix()."users.manager_id IN (select id from ".DB::getTablePrefix()."users where first_name LIKE ? OR last_name LIKE ?)", ["%$search%", "%$search%"]);
});
+1 -1
View File
@@ -45,7 +45,7 @@ class CheckinNotification extends Notification
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance() == '1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
// $notifyBy[] = 'mail';
}
}
return $notifyBy;
@@ -0,0 +1,67 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class FirstAdminNotification extends Notification
{
use Queueable;
private $_data = array();
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct(array $content)
{
$this->_data['email'] = $content['email'];
$this->_data['first_name'] = $content['first_name'];
$this->_data['last_name'] = $content['last_name'];
$this->_data['username'] = $content['username'];
$this->_data['password'] = $content['password'];
$this->_data['url'] = url('/');
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject(trans('mail.welcome', ['name' => $this->_data['first_name'] . ' ' . $this->_data['last_name'] ]))
->markdown('notifications.FirstAdmin', $this->_data);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
namespace App\Notifications;
use App\Models\Settings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class MailTest extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject(trans('mail.test_email'))
->markdown('notifications.Test');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

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