Compare commits

...

490 Commits

Author SHA1 Message Date
snipe ea0a0a4a69 Merge branch 'develop' 2017-10-18 02:35:43 -07:00
snipe 34442362ca Fixes bad route for new groups 2017-10-18 02:35:30 -07:00
snipe b846bb20c6 Merge branch 'develop' 2017-10-18 01:23:01 -07:00
snipe ab3f5f4f4d Bumped version 2017-10-18 01:21:50 -07:00
snipe ea63ced2bd Fixes table alias bug in complex queries for Laravel 2017-10-18 01:21:08 -07:00
snipe 6bd49bfb72 Fixes #4191 - user search 2017-10-18 01:20:50 -07:00
snipe b80d3ce50d Hopefully fixes #4218 2017-10-18 00:36:52 -07:00
snipe c069829b33 Fixes #906 - groups view 2017-10-17 21:43:57 -07:00
Geoff Young 665a113ed8 Update account history query (#4237)
This will limit the action_log records displayed when a user is viewing
their own assets and history since both target_type and target_id must
be set for a where condition to be added to the history query.
2017-10-17 20:39:49 -07:00
snipe aa7091d962 Fixes #4226 - adds log_max_files to app config and sample env 2017-10-17 20:04:07 -07:00
snipe ceff6a9617 Merge branch 'develop' 2017-10-17 19:27:31 -07:00
snipe c01850fc73 Corrected Italian to Irish in language selector 2017-10-17 19:19:46 -07:00
snipe 4c04dc7b84 Merge branch 'develop' 2017-10-17 18:55:49 -07:00
snipe c0103cd878 Bumped version 2017-10-17 18:55:30 -07:00
snipe 1f1d9d5461 Merge branch 'develop' 2017-10-17 18:53:21 -07:00
snipe c776fa4f7b Updated language strings 2017-10-17 18:52:20 -07:00
snipe dc91d10395 More possible fixes for #4210 2017-10-17 17:35:48 -07:00
snipe 4df10ad26c Merge branch 'develop' 2017-10-17 17:19:15 -07:00
snipe 668a88bc86 Add autocomplete=off to settings forms for #4210 2017-10-17 17:18:17 -07:00
snipe d6e0012818 Merge branch 'develop' 2017-10-17 17:05:38 -07:00
snipe 1d5fb52bfc Fix for LDAP where location ou is not null but blank 2017-10-17 16:59:50 -07:00
snipe 8efb02a0ee Merge branch 'develop' 2017-10-17 16:23:59 -07:00
snipe dea42db18b Reversed order of withTrashed for deleted asset QR codes 2017-10-17 16:21:50 -07:00
snipe 78d5d3947f Merge branch 'develop' 2017-10-17 16:18:14 -07:00
snipe a1f5e11517 Fix for broken QR code on deleted assets 2017-10-17 16:01:53 -07:00
snipe 99ad096a8a Added a space next to crowdin badge 2017-10-17 15:26:16 -07:00
snipe 65b4ffeed9 Higher res crowdin badge 2017-10-17 15:25:34 -07:00
snipe 0dac88816a Merge branch 'develop' of github.com:snipe/snipe-it into develop
# Conflicts:
#	README.md
2017-10-17 15:20:53 -07:00
snipe f7626404b7 Add @BlueHatbRit as a contributor 2017-10-17 15:18:27 -07:00
Elliot Blackburn 78f4b08398 Change zenhub markdown shield to higher res (#4235)
The zenhub badge was fuzzy as it was a low resolution for retina display. It's now using a new shield which falls in line with some of the others (img.shield.io).
2017-10-17 15:16:49 -07:00
snipe 160fd1c86a Added setting to let admin decide whether footer text should link back to site 2017-10-17 13:54:03 -07:00
snipe 6ce01487c5 Merge branch 'develop' 2017-10-17 13:31:43 -07:00
snipe b46cbac911 Fixes #4230 - adds model name and manufacturer to emails 2017-10-17 13:30:32 -07:00
snipe e9c3d6bfb7 Full text search fixes - addresses laravel bug :( 2017-10-17 12:48:18 -07:00
snipe 9e9a5b7a53 Changed checkin/checkout buttons to different colors for easier visibility 2017-10-17 11:32:09 -07:00
snipe e7fe91c9d4 Depreciation view 2017-10-17 11:20:05 -07:00
snipe 6d130326aa Merge branch 'develop' 2017-10-16 21:28:23 -07:00
snipe 02db0f9f9d Handle deleted assets in maintenance 2017-10-16 21:28:05 -07:00
snipe e0668b7507 Handle references to suppliers that have been deleted 2017-10-16 21:19:06 -07:00
snipe 1376f246dc Merge branch 'develop' 2017-10-16 20:38:19 -07:00
snipe 113c55d905 Hopefully fixes #4150 2017-10-16 20:34:31 -07:00
snipe 9cc25bcfd0 Hopefully fixes #4150 2017-10-16 20:34:22 -07:00
snipe 81d3f78263 Production assets 2017-10-16 20:12:42 -07:00
snipe 66596b0b09 Production assets 2017-10-16 20:12:22 -07:00
snipe 7455b1019a Hacky possible fix for subdir issues 2017-10-16 20:12:11 -07:00
snipe 37df934e97 Fixes #4220 - allow nullable for completion date 2017-10-16 18:32:48 -07:00
snipe 6517a95d45 Check if there are any custom fields before trying to loop through them 2017-10-16 15:29:19 -07:00
snipe 4b84a0c916 Tidying some of the LDAP UDN logic 2017-10-16 15:29:06 -07:00
snipe 0f0a61e477 Merge branch 'develop' 2017-10-16 10:10:29 -07:00
snipe f64382aa00 Nicer error display in LDAP tests 2017-10-16 10:10:11 -07:00
snipe 1743417ec9 Merge branch 'develop' 2017-10-16 09:38:26 -07:00
snipe c61bed52c8 Removed danger class 2017-10-16 09:38:09 -07:00
snipe edf75865dc Merge branch 'develop' 2017-10-16 09:27:01 -07:00
snipe 176a26e6c3 Bumped version 2017-10-16 09:26:44 -07:00
snipe 10a4d7e849 Merge branch 'develop' 2017-10-16 09:09:53 -07:00
snipe cbe008d52f Fix assetLoc to assetloc because reasons? 2017-10-16 09:08:08 -07:00
snipe aeb5152789 Removed extranneous class for danger text 2017-10-16 09:04:38 -07:00
snipe 938490df16 Merge branch 'develop' 2017-10-16 09:01:09 -07:00
snipe 45c2af80a3 More LDAP testing US refinements 2017-10-16 09:00:51 -07:00
snipe 892c1b04fd Merge branch 'develop' 2017-10-16 07:07:35 -07:00
snipe 1fbf3753bc More small LDAP test improvements 2017-10-16 07:07:21 -07:00
snipe 5ead5a94e3 Merge branch 'develop' 2017-10-16 06:47:01 -07:00
snipe bcf435f625 Try for better error reporting on LDAP fail
Sorry for all the commits on this - my local LDAP isn’t working and I can’t figure out why, so no easy way to test locally
2017-10-16 06:46:33 -07:00
snipe 8638c46b1d Merge branch 'develop' 2017-10-16 06:40:15 -07:00
snipe b107280b7b Slightly nicer UI for LDAP login test 2017-10-16 06:39:36 -07:00
snipe 1a60c20117 Merge branch 'develop' 2017-10-16 06:34:23 -07:00
snipe f1a6926ad9 LDAP test login 2017-10-16 06:34:04 -07:00
snipe c27a7f09bd Merge branch 'develop' 2017-10-16 05:55:27 -07:00
snipe ba7b9d8168 Removed stray foo 2017-10-16 05:54:33 -07:00
snipe 5b070ee32f Merge branch 'develop' 2017-10-16 05:52:52 -07:00
snipe 59a126c47c Small tweaks to LDAP test 2017-10-16 05:52:18 -07:00
snipe 322e62418e Merge branch 'develop' 2017-10-16 05:23:26 -07:00
snipe a98d94ccdc Pass token to LDAPtest 2017-10-16 05:22:37 -07:00
snipe 5addcb517f Merge branch 'develop' 2017-10-16 05:01:37 -07:00
snipe 56cbc005ae Fixes expected checkins name in console kernel 2017-10-16 05:01:15 -07:00
Daniel Meltzer 22e9246031 Fix more old routes. Should fix #4216 (#4217) 2017-10-15 23:32:40 -07:00
snipe c0b39701cc Fixes #4170 - asset maintenance type not showing 2017-10-14 16:17:14 -07:00
madd15 e2bac62e36 Fix #4205 (#4213)
* Fixing various UI items

* Revert css change

* Dashboard icon CSS up 4px
2017-10-14 00:14:22 -07:00
snipe c12a23b84a Merge branch 'develop' 2017-10-11 15:37:01 -07:00
snipe fa95f6d836 Another attempt for #4165 2017-10-11 15:36:47 -07:00
snipe 280e8c7ed1 Revert "Another attempt for #4165"
This reverts commit 7617fda978.
2017-10-11 15:34:30 -07:00
snipe 7617fda978 Another attempt for #4165
(This is terrible and needs to be refactored.)
2017-10-11 15:33:53 -07:00
snipe af69f7636b Merge branch 'develop' 2017-10-11 14:44:37 -07:00
snipe 6d4574130f Clearer indication of whether or not the user will be emailed a eula 2017-10-11 14:44:25 -07:00
snipe 485b6397d0 Possible (crummy temp) fix for #4165 2017-10-11 14:42:11 -07:00
snipe 93990327de Hopefully fixes #4163 2017-10-11 14:18:08 -07:00
madd15 4ee7765403 Change Save buttons to Checkout and add Cancel (#4202)
Bringing components and consumables checkout page inline with other
checkout pages
2017-10-11 13:29:22 -07:00
snipe bdbad067b4 Merge branch 'develop' 2017-10-11 13:10:46 -07:00
snipe 13a716310c Bumped hash 2017-10-11 13:10:29 -07:00
snipe d0c77c228b Merge branch 'develop' 2017-10-11 13:09:30 -07:00
snipe 36cbffa183 Fixes bug where custom fields would not store new name in custom fields table on edit 2017-10-11 13:09:10 -07:00
snipe 5edf9e143f Merge branch 'develop' 2017-10-11 12:46:42 -07:00
snipe b6a1e0d12f Call migrate before passport install 2017-10-11 12:42:31 -07:00
snipe 2fda3a2d26 Merge branch 'develop' 2017-10-11 12:29:48 -07:00
snipe f56eb16941 More specific order by clause for drilling down on order number 2017-10-11 12:29:08 -07:00
snipe c15c082fb4 Merge branch 'develop' 2017-10-11 01:31:59 -07:00
snipe 64e7ab3a12 Fixes #4182 - empty names for assets when checking out to asset 2017-10-11 01:31:37 -07:00
snipe afbd6c811b Merge branch 'develop' 2017-10-10 23:38:45 -07:00
snipe f64c02ce12 Fix for ambiguous query on models 2017-10-10 23:12:16 -07:00
snipe a0d8aa77d3 Merge branch 'develop' 2017-10-10 22:59:50 -07:00
snipe bed7b29417 Fixes group search 2017-10-10 22:59:32 -07:00
tiagom62 40ed86bfe0 Sudo isnt available on every distro. (#4194) 2017-10-10 22:02:47 -07:00
snipe 33497c9811 Merge branch 'develop' 2017-10-10 12:48:05 -07:00
snipe 52a8597813 Fixes #4136 2017-10-10 12:44:28 -07:00
snipe eeb07f73e5 Added Redis vairables to example env 2017-10-09 15:44:08 -07:00
Alex Markessinis 57422c9135 Added Redis support. (#4146)
* Fix forgotten password missing route (???)

* Fixes #4056 - check for assets before deleting user

* added predis/predis dependency to composer.json to support redis based cache/queue/session/broadcast
2017-10-09 15:39:20 -07:00
Richard Hofman adca7cb0c5 Fix LDAP location sync issue in #3993 (#4181)
* Ensure locations with the most specific OUs take precedence during user assignment.

* Save 'ldap_ou' Location attribute during creation.
2017-10-09 13:06:47 -07:00
Richard Schwab 059f8f5bc9 Remove dead macro code (#4164)
The barcode_types macro existed twice in the code, the second occurrence overriding the first one.
This commit removes the first occurrence which is essentially dead code.
2017-10-09 13:06:05 -07:00
tiagom62 c676e9d794 Fix progress spinner. (#4178) 2017-10-09 13:04:48 -07:00
Daniel Meltzer e9f10dd74e Maybe Fix #4052. Missed an absolute URL. (#4187) 2017-10-09 13:04:38 -07:00
snipe e29d878d4f Remove unused method arguments 2017-10-07 15:09:50 -07:00
snipe d4e3ea1412 Derp 2017-10-07 15:07:31 -07:00
snipe c5462c5f1f Not sure why this isn’t working… commenting it out for now 2017-10-07 14:52:00 -07:00
snipe d1328c3ba9 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-07 14:49:54 -07:00
snipe 8c406e8e55 Additional auth policies 2017-10-07 14:49:47 -07:00
snipe 6e33f36595 Set snipe-logo as default 2017-10-07 14:49:36 -07:00
tiagom62 48277606de Support Debian 8 installs. Shellchecked. More cleanup. (#4174) 2017-10-07 12:45:25 -07:00
snipe d7c9fcc8df Small manufacturer display tweaks on license view to make text clearer, link phone 2017-10-07 08:27:56 -07:00
snipe 508576544b Merge branch 'develop' 2017-10-07 08:17:58 -07:00
snipe 9f2fc21649 I guess we don’t need to manually create the license seats 2017-10-07 08:17:38 -07:00
snipe 11f99a963a Removed extra comma in demo warning 2017-10-07 08:03:08 -07:00
snipe 27ab0271a1 Merge branch 'develop' 2017-10-07 08:00:11 -07:00
snipe f858b2858d Add language about the demo resetting daily to en files 2017-10-07 07:59:57 -07:00
snipe e2809f7bd0 Merge branch 'develop' 2017-10-07 07:45:58 -07:00
snipe f468b37f36 Bumped hash 2017-10-07 07:45:43 -07:00
snipe 0b3d3de30f Merge branch 'develop' 2017-10-07 07:44:30 -07:00
snipe 907b909223 Fixed language on settings page 2017-10-07 07:44:08 -07:00
snipe 9dc79f7165 Demo Settings reset artisan command
We’ll set this as a cron job to reset the language back to english
2017-10-07 07:43:57 -07:00
snipe 324d44dbac Small accessory factory tweaks 2017-10-07 07:24:15 -07:00
snipe 7a0e695ea0 Merge branch 'develop' 2017-10-07 07:17:05 -07:00
snipe a69a939034 Small barcode tweaks 2017-10-07 07:15:28 -07:00
snipe ed8efbe759 Add dateFormatter to components view 2017-10-07 06:57:02 -07:00
snipe 834c6ad8f9 Removed extra space 2017-10-07 06:56:47 -07:00
snipe 2ce48fbc7e Use components transformer in API method 2017-10-07 06:56:39 -07:00
snipe 5d18937e94 Standardized component API output 2017-10-07 06:56:18 -07:00
snipe b3186ba5ea Removed old getDataTable methods
These are no longer used because of the API
2017-10-07 06:56:02 -07:00
snipe f51dc9a1c4 Use recent date range for factory 2017-10-07 06:17:39 -07:00
snipe f3f9920bd3 Added Crucial as a manufacturer in factory 2017-10-07 06:17:18 -07:00
snipe ea6140e786 Components factory and seeder 2017-10-07 06:16:53 -07:00
snipe 05c4d6dead Make HDD into HDD/SSD for factory 2017-10-07 06:16:36 -07:00
snipe e2c6f36c70 Use recent date range for factory 2017-10-07 06:16:21 -07:00
snipe 21b1ecb6b3 Only checkout RTD assets 2017-10-07 06:16:06 -07:00
snipe a62cf358ee More realistic prices for factories 2017-10-07 05:52:44 -07:00
snipe 20c429b600 Add some archived and pending assets too 2017-10-07 05:52:26 -07:00
snipe 38e25a388c lol whoops 2017-10-07 05:34:13 -07:00
snipe 2c6cedd62c Removed unused factories 2017-10-07 05:32:59 -07:00
snipe 9b0cca4a37 Added licensed to name, email to licenses factory 2017-10-07 05:32:39 -07:00
snipe f6d198a39c Added back in some unused asset stuff for tests 2017-10-07 05:32:22 -07:00
snipe d12fc6b13c Add depreciation ID to model factories 2017-10-07 05:32:00 -07:00
snipe a12c7c83d4 Req acceptance on laptop category 2017-10-07 05:31:46 -07:00
snipe affd4035c3 Added displays to seeders 2017-10-07 05:31:32 -07:00
snipe ecfe1a5442 Depreciations factory 2017-10-07 05:30:53 -07:00
snipe e9c77198d7 Fix duplicate call to licenses seeder 2017-10-07 04:54:16 -07:00
snipe 20be670648 Fixed ids for license 2017-10-07 04:43:55 -07:00
snipe a03207e5b4 Show license notes 2017-10-07 04:42:53 -07:00
snipe 6555b3a49d No location id in licenses? 2017-10-07 04:36:23 -07:00
snipe 61a634bc1a No idea why this worked locally before, but… 2017-10-07 04:34:51 -07:00
snipe 00696a3668 Commented out slow users factories right now - will revert when finished 2017-10-07 04:26:37 -07:00
snipe e20271791b Removed unused factories for now
Need to add these back, once the correct logic is applied
2017-10-07 04:26:21 -07:00
snipe 86b9fdbffe License and actionlog seeder tweaks 2017-10-07 04:25:35 -07:00
snipe 7e728094a1 User seeders 2017-10-07 03:41:46 -07:00
snipe f865c621ef Removed commented code 2017-10-07 03:41:40 -07:00
snipe e2f4685a55 Added notes back to list view 2017-10-07 03:36:50 -07:00
snipe 2148ea94bb Additional model seeders 2017-10-07 03:19:46 -07:00
snipe 1d2787250b Reference IDs 2017-10-07 03:19:27 -07:00
snipe 7f02ff12cf Asset seeder 2017-10-07 03:19:17 -07:00
snipe 65341a5d8a Added ID reference numbers 2017-10-07 03:19:07 -07:00
snipe 1608edbb28 Added ID reference numbers 2017-10-07 03:18:57 -07:00
snipe 776da1dea4 Add Dept seeder to db seeder 2017-10-07 03:18:46 -07:00
snipe a6b3e4bbb1 Department seeder/factory 2017-10-07 03:18:36 -07:00
snipe 3b2ecda243 Consumables factory/seeder 2017-10-07 02:46:04 -07:00
snipe 57cbb5c5ce Removed unused factories 2017-10-07 02:45:54 -07:00
snipe 7b27d32121 Added ID numbers 2017-10-07 02:45:36 -07:00
snipe ccfba324ee Indenting 2017-10-07 02:45:28 -07:00
snipe 9f55a76fcf Added avery 2017-10-07 02:45:21 -07:00
snipe 8fdddc310f More rigid seeders for more realistic data 2017-10-07 02:27:02 -07:00
snipe 064a4ebe33 Ability to skip deleting/generating new users
This will behave unpredictably if there is not a user id 1
2017-10-07 00:02:37 -07:00
snipe 4981077cb1 Merge branch 'develop' 2017-10-06 22:59:01 -07:00
tiagom62 fbea1c0823 Code dedupe, general cleanup and added a verbose option for debugging. (#4173) 2017-10-06 22:58:41 -07:00
snipe a84da88114 Demo seeder 2017-10-06 22:58:00 -07:00
snipe 282b3b5b0a Remove catch-all “deployed” from pie chart 2017-10-06 18:41:10 -07:00
snipe 130a99c46f Merge branch 'develop' 2017-10-06 18:15:31 -07:00
snipe df4cb7d351 Don’t reload the page if the API returns a 500 2017-10-06 18:15:13 -07:00
snipe 1dcff8d463 Remove eager loading on pie
This was causing memory issues for large asset sets
2017-10-06 18:15:01 -07:00
snipe ae4ba6176d Merge branch 'develop' 2017-10-06 17:04:06 -07:00
snipe e461c25428 Apply model image fix to update method 2017-10-06 17:03:51 -07:00
snipe ea4bfdc51d Merge branch 'develop' 2017-10-06 16:57:51 -07:00
snipe 554ea8bb95 Fixed asset model image validation 2017-10-06 16:56:43 -07:00
Richard Hofman f2be409914 LDAP sync improvements and DB query fix. (#4148)
* Set 'ldap_ou' Location field to NULL when an empty string is submitted.

* Consolidate LDAP user import logic in LdapSync.php.
2017-10-06 16:15:14 -07:00
snipe 3fc1bbea73 Apply PR changes to master. Again? 2017-10-06 14:28:19 -07:00
snipe a97f7d2277 Merge branch 'develop' 2017-10-06 14:27:46 -07:00
snipe af70cdaeac Adds email address to CoC 2017-10-06 13:44:39 -07:00
snipe 8919c3b52a Merge branch 'develop'
# Conflicts:
#	snipeit.sh
2017-10-05 23:14:13 -07:00
snipe f580e20bc3 Fixed custom fields filter for advanced search 2017-10-05 23:09:02 -07:00
snipe a054cec7c9 Supress output if no title is given
This should never happen, but….
2017-10-05 22:51:33 -07:00
tiagom62 1ad7bbdd0c Support configuring smtp settings (#4161)
* Able to configure smtp settings. General cleanup.

* Check if sudo is available.
2017-10-05 21:27:00 -07:00
snipe cfe6759825 Merge branch 'develop' 2017-10-05 00:41:30 -07:00
snipe 10c13baf2b Add @GeoffYoung as a contributor 2017-10-05 00:40:32 -07:00
snipe 9fe4e11874 Merge branch 'develop'
# Conflicts:
#	snipeit.sh
2017-10-05 00:37:16 -07:00
snipe f6d8642799 Fix $search variable to $search_var for new filter 2017-10-05 00:35:37 -07:00
snipe adddc5324b Add @imjennyli as a contributor 2017-10-05 00:34:50 -07:00
snipe f442b70ae7 Apply PR #4133 to develop 2017-10-05 00:02:14 -07:00
madd15 7b10213b3a Small UI Tweaks to Accessories (#4149)
* Small UI Change

Changing Save button for Checkout button and adding Cancel button

* Small UI Change

Move buttons to match checkout page and remove extra save button
2017-10-04 23:28:13 -07:00
tiagom62 ddc79b9070 Support Ubuntu and Debian installs. (#4133)
* Ubuntu related fixes.

* Further cleanup.

* Support Debian 9 install. More cleanup.
2017-10-04 23:19:38 -07:00
Jenny Li 5e9b04b0f5 update broken link to contributor docs (#4123) 2017-10-04 23:19:19 -07:00
snipe 2562eb2aeb Merge branch 'develop' 2017-10-03 21:23:46 -07:00
snipe 85da30894b Bumped version 2017-10-03 21:23:27 -07:00
snipe bf344e9322 Merge branch 'develop' 2017-10-03 21:03:19 -07:00
snipe f66e222f3d Fixes #4132 - associated accessory users 2017-10-03 21:03:00 -07:00
snipe fb180d74a1 Merge branch 'develop' 2017-10-03 18:12:47 -07:00
snipe eaf55f5e79 Hide table toolbar id models are deleted 2017-10-03 18:12:30 -07:00
snipe 8edb586576 Merge branch 'develop' 2017-10-03 18:06:59 -07:00
snipe 32b01b8f38 Toggle button deleted/not for models 2017-10-03 18:06:41 -07:00
snipe 340386f282 Merge branch 'develop' 2017-10-03 17:55:21 -07:00
snipe 6dd4282f1f Fixes #4130 - show deleted asset models 2017-10-03 17:53:08 -07:00
snipe 3f44987799 Small logo size tweaks 2017-10-03 14:15:03 -07:00
snipe b4fec068d0 Use asset url for favicon on login blade 2017-10-03 13:44:50 -07:00
snipe 512632ce60 Make the export button contextual for requested status 2017-10-03 12:50:18 -07:00
snipe 58a9b0d3e8 Normalized route name 2017-10-03 12:50:01 -07:00
snipe fcb1283a14 Added missing deployed page title 2017-10-03 12:49:53 -07:00
snipe 54671af7f0 Small export assets fix 2017-10-03 11:49:41 -07:00
snipe aedabb0920 Merge branch 'develop' 2017-10-03 11:29:06 -07:00
snipe aaf4acef83 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-03 11:28:45 -07:00
snipe 8e73cacf4e Fixes custom report to include assigned to names, etc 2017-10-03 10:38:28 -07:00
Daniel Meltzer b4b2daebbd Fix Importer tests. (#4122) 2017-10-03 09:14:04 -07:00
snipe 3e2c18cb4d Merge branch 'develop' 2017-10-03 08:47:57 -07:00
snipe c721fdd793 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-03 08:46:25 -07:00
Daniel Meltzer d119372ff0 Fix License Import. (#4121)
The license name is not unique, so keying by license alone was causing issues.  Match using name + serial instead.
2017-10-03 08:46:06 -07:00
snipe c8bed867da Export PDF as landscape 2017-10-03 07:32:18 -07:00
snipe 3a470ce789 Only report exceptions we want to see 2017-10-03 07:28:00 -07:00
snipe f9105719a8 Merge branch 'develop' 2017-10-03 05:16:11 -07:00
snipe d303cbd7cb Bumped version 2017-10-03 05:15:52 -07:00
snipe 96c09e7264 Merge branch 'develop' 2017-10-03 02:05:47 -07:00
snipe ef19bc7c16 Workaround to fix #4117
This shouldn’t be necessary, but it looks like some folks missed the migration that drops the FK for company_id
2017-10-03 02:05:22 -07:00
snipe aa8472971d Merge branch 'develop' 2017-10-02 21:58:17 -07:00
snipe 78257d5ca6 Merge branch 'develop' 2017-10-02 21:55:25 -07:00
tiagom62 655484b1da General cleanup and get ubuntu install working. (#4118) 2017-10-02 21:37:04 -07:00
snipe ac8185339d Removed linebreaks 2017-10-02 20:32:42 -07:00
snipe a021ce011b Correct argv 2017-10-02 20:31:43 -07:00
snipe 3687cbfdb3 Added rollbar support 2017-10-02 20:27:45 -07:00
snipe 594135fd70 Upgrade script improvements 2017-10-02 20:11:07 -07:00
snipe 2542b9cf59 Merge branch 'develop' 2017-10-02 17:21:36 -07:00
snipe 8a7abba427 Slash url 2017-10-02 17:21:18 -07:00
snipe 3775649c8a Merge branch 'develop' 2017-10-02 17:19:59 -07:00
snipe 9df648b428 Fix Session path 2017-10-02 17:19:22 -07:00
snipe 11a1efdbbc Merge branch 'develop' 2017-10-02 16:56:12 -07:00
snipe a65c2f305e Set polict to same-origin in example env 2017-10-02 16:47:19 -07:00
snipe 50777f5c1d Merge branch 'develop' 2017-10-02 16:39:11 -07:00
snipe ff38cdd09b Comment out the nullable middleware until we have a chance to check all model validators 2017-10-02 16:36:43 -07:00
snipe 9420913d25 Set referrer policy to same origin - should fix a lot of weird validation redirects 2017-10-02 16:35:57 -07:00
snipe 59225701b5 Redirect to previous after login 2017-10-02 16:00:42 -07:00
snipe 6aa5d4d58c Merge branch 'develop' 2017-10-02 15:27:33 -07:00
snipe cd2e137fcc Bumped version 2017-10-02 15:27:18 -07:00
snipe 0b968e1d6b Merge branch 'develop' 2017-10-02 13:31:08 -07:00
snipe 7a27fda083 Update example env with CSP default 2017-10-02 13:29:42 -07:00
snipe aab635154a Default to turning CSP off until we can fix vue/CSP issues 2017-10-02 13:29:14 -07:00
snipe e389f67629 Merge branch 'develop' 2017-10-02 13:09:17 -07:00
Geoff Young 169dc779fd Fix box title in Label settings view (#4111) 2017-10-02 13:00:32 -07:00
tiagom62 26423c5c02 Fix various installer issues. (#4096)
* Various installer fixes.

* CentOS 6 related fixes.
2017-10-02 12:59:53 -07:00
snipe 862543428b Fix named route for license checkin 2017-10-02 12:58:17 -07:00
snipe d28e882f5d Fixed form close tag 2017-10-02 12:57:01 -07:00
snipe e26d038589 Fixed license checkin form UI 2017-10-01 15:08:32 -07:00
snipe afc8133acf URL nullable validation isn’t working in Laravel 5.4? 2017-10-01 14:40:13 -07:00
snipe abe19a6311 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-01 14:33:02 -07:00
snipe 07359c76ad Fixes #4094 - more nullables 2017-10-01 14:32:47 -07:00
Daniel Meltzer a2453be573 Pass urls to passport vue components to make work in subdirectories. (#4090) 2017-10-01 13:59:07 -07:00
Daniel Meltzer c2616412c0 Add laravel routes to javascript (#4092)
* Add laravel routes to javascript

This will clean up a lot of passing of urls.  Adds a route() helper and
everything...

This commit also moves the customfield fetching to only be fetched once
and shared with each file, rather than once for each file.

* Try to fix travis unit test things.

* Downgrade doctrine/inflector for php5

* Attempt to occasional seeder issues on travis if the asset does not generate validatable data.

* Update sql dump for functional tests.

* Try to fix api tests.
2017-10-01 12:59:55 -07:00
Daniel Meltzer 23ca2d9a0b Minor fixes (#4091)
* Fix old urls.

Still had some /admin/ urls floating around, which was causing bad
redirects in some instances.  Should fix #4085

* The modal seems to be confusing license upload. be more explicit in the route we redirect to.

* Fix #4039.  Use proper methods for location assets.

This also fixes a bunch of n+1 issues in the transformer.  Also: curious
to know what Location::assets() does, because it doesn't do what I want
it to :)
2017-10-01 12:57:04 -07:00
snipe 0bb186ad3b Prod manifest 2017-09-29 19:43:33 -07:00
snipe b7abd8328a Prod asset build 2017-09-29 19:43:18 -07:00
snipe ad2821b4ab Merge branch 'develop' 2017-09-29 17:57:48 -07:00
snipe 7d5b08446a Missing colon in status explanations 2017-09-29 17:52:43 -07:00
snipe ba793355cb Nullable crap. Again. 2017-09-29 17:50:52 -07:00
Daniel Meltzer 655ca78633 Adjust the import controller to return a url to the process path to enable processing an uploaded file without refresh. (#4080) 2017-09-29 17:49:35 -07:00
snipe f00dcb57cf Merge branch 'develop' 2017-09-29 17:39:09 -07:00
snipe 1e52fb546c Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-29 17:32:25 -07:00
snipe 24cad588bd Added preceding icons in polymorphic formatter 2017-09-29 17:32:16 -07:00
Daniel Meltzer bbffde47f7 Remove conditional related to no longer existant testrun option. (#4079) 2017-09-29 17:31:39 -07:00
snipe be7598b279 Fixes all assets showing as unassigned in license checkout 2017-09-29 17:14:38 -07:00
snipe 1a7e3fbb4b Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-29 17:05:32 -07:00
Daniel Meltzer e8a0c44e93 Update some composer dependencies to try to fix everything breaking in subdirectories. Attempts to fix #4052, it seems to help here. (#4078) 2017-09-29 17:05:20 -07:00
snipe fe644c76c5 Better explanations of how status label metas work 2017-09-29 17:03:21 -07:00
snipe 9301c56a77 Fixes #4069 - include request handler 2017-09-29 16:17:35 -07:00
snipe e37503c734 Fixes #4075 - this is janky and should be revisited 2017-09-29 16:09:24 -07:00
snipe 6bc3f194ec Merge branch 'develop' 2017-09-29 15:59:40 -07:00
snipe 878bde67ac Few more issue template tweaks 2017-09-29 15:59:04 -07:00
snipe 314d6fa4c5 Expanded issue template 2017-09-29 15:55:58 -07:00
snipe 43ff66e4d9 More UI tweaking for meta statuses 2017-09-29 15:24:33 -07:00
snipe 2ea91266c0 Init lightbox 2017-09-29 14:26:00 -07:00
snipe a0bd9bce39 Commented out security headers - might req apache module 2017-09-29 14:00:05 -07:00
snipe 5223ec1dbb Clearer status listing in the sidenav 2017-09-29 12:13:15 -07:00
snipe 4eda2a2f96 *ahem* 2017-09-29 12:03:12 -07:00
snipe fe1975067a Hopefully clearer status label meta info 2017-09-29 12:03:02 -07:00
snipe b9e79c27a8 Added nonce to basic blade 2017-09-29 05:49:26 -07:00
snipe b8ed6a53b6 For #3998 - Added nonce to all.js 2017-09-29 04:53:24 -07:00
snipe efd71f8bfe For #3998 - Disable CSP if debug=true
To avoid all the nonce hell from debugbar
2017-09-29 04:53:09 -07:00
snipe 05a8ba9a8e Fix weird url if license checkout fails 2017-09-29 04:37:33 -07:00
snipe 9ce2d1f560 Merge branch 'csp-middleware' into develop 2017-09-29 04:14:33 -07:00
snipe 5a1225a8bf Merge branch 'develop' 2017-09-29 03:48:37 -07:00
snipe c6069b905b Bumped version 2017-09-29 03:47:50 -07:00
snipe 2e76620cf8 More specific required check 2017-09-29 03:44:23 -07:00
snipe a4b30279ee Fixes #4067 - Make unrequired custom fields nullable 2017-09-29 03:30:13 -07:00
snipe db59d4b2c4 Merge branch 'develop' 2017-09-29 02:08:06 -07:00
snipe faf3802971 Fixes #4011 - do not send email to user on license checkout 2017-09-29 02:00:49 -07:00
snipe 7fe2a1f802 Fixes #4051 - use delete method for deleting user files 2017-09-29 01:48:16 -07:00
snipe 3d57d1bd1d Merge branch 'develop' 2017-09-29 01:30:30 -07:00
snipe ba8bcce8eb Hopefully fixes #4020 2017-09-29 01:21:08 -07:00
snipe 8247a73182 Merge branch 'develop' 2017-09-28 22:22:37 -07:00
snipe aab409dec2 Fixes #4061 - bulk checkout error 2017-09-28 22:22:21 -07:00
snipe 70a9b7bf05 Merge branch 'develop' 2017-09-28 21:21:01 -07:00
snipe d9824a0454 Bumped version 2017-09-28 21:20:37 -07:00
snipe e759a249bd Merge branch 'develop' 2017-09-28 21:18:39 -07:00
snipe 42c2a66946 Small UI tweaks for accessories 2017-09-28 21:18:16 -07:00
snipe 4d32f2b337 Fixes #4059 - accessories view 2017-09-28 21:18:00 -07:00
snipe 0e29744ec2 Don’t try to send an email if the user doesn’t have an email address 2017-09-28 20:57:33 -07:00
snipe 51236a2ad9 Fixes #4056 - check for assets before deleting user 2017-09-28 19:57:52 -07:00
snipe 9b6726a630 Fixes #4056 - check for assets before deleting user 2017-09-28 19:57:03 -07:00
snipe cbdd05144a Merge branch 'develop' 2017-09-28 19:50:34 -07:00
snipe 46d87849f4 Added content security middleware 2017-09-28 19:45:15 -07:00
snipe 507f1f196c Added integrity hashes 2017-09-28 18:46:16 -07:00
snipe b60febeea2 Removed space in XSS header because safari was getting angry 2017-09-28 18:45:54 -07:00
snipe b3e0d8f675 Disallow / in robots 2017-09-28 17:47:48 -07:00
snipe 9b84a0d516 *eyeroll* 2017-09-28 17:34:47 -07:00
snipe adac5ac544 Check for valid asset 2017-09-28 17:32:37 -07:00
snipe 1775995f26 Is this space necessary? Getting weird results from netsparker 2017-09-28 17:25:04 -07:00
snipe df4700b411 Merge branch 'develop' 2017-09-28 17:17:03 -07:00
snipe 26a7701cda Added referrer-policy header 2017-09-28 17:12:58 -07:00
snipe a34085f1d9 Added mode=block to XSSProtect header 2017-09-28 16:28:27 -07:00
snipe 8e682c715e Merge branch 'develop' 2017-09-28 16:07:04 -07:00
snipe 915c19ebda Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-28 16:03:41 -07:00
snipe 7fded367c4 Adds rel="noopener" to footer links 2017-09-28 16:03:36 -07:00
Daniel Meltzer 0a4743210c Pass urls to vue. Should fix subdirectory issues. (#4054) 2017-09-28 16:03:04 -07:00
Daniel Meltzer af19e5d976 Fix old route (#4053)
Looks like we missed in the v4 port.  Fixes the unrelated issue in #4052
2017-09-28 16:02:50 -07:00
snipe 3d7277398c Fixes #4057 - sig file in lightbox 2017-09-28 15:13:05 -07:00
snipe a7ad48a02a Make fields nullable for licenses 2017-09-27 22:11:20 -07:00
snipe 469a3fc608 Merge branch 'develop' 2017-09-27 17:48:32 -07:00
snipe 0fb4ff77f4 Restoring older SnipeModel attribute setters
In case needed by API - needs investigation
2017-09-27 16:39:20 -07:00
snipe ac83dba2bb Fixes #4034 - save login note 2017-09-27 16:35:54 -07:00
snipe 979ecf961d Added back button to oauth page 2017-09-27 16:33:51 -07:00
snipe 13dcdf41b8 Fixes #4045 - missing back button 2017-09-27 16:32:37 -07:00
snipe fc96fa756e Fix redirect default on password reset 2017-09-27 16:23:21 -07:00
snipe ea9a502152 Added empty regsitration controller
When using the default Laravel auth routes, it expects a registration controller, even though we don’t have a concept of registration. This blank controller just prevents route caching from throwing errors.
2017-09-27 16:23:01 -07:00
snipe d844734b6c Use named login route 2017-09-27 16:22:02 -07:00
snipe ec8a3d2e56 Fixes #4027 - proper redirect on fieldset delete 2017-09-27 16:02:29 -07:00
snipe 5410dc4255 Fixed link to contributing docs in readme 2017-09-27 15:30:20 -07:00
snipe d1112bbc99 Fix created_at date display for groups index 2017-09-27 15:28:02 -07:00
snipe ecf041fa10 Fixes #4043 - standardize groups API response 2017-09-27 15:18:29 -07:00
snipe 0ab9bc1db8 Added normalization midddleware, removed 2017-09-27 15:18:05 -07:00
snipe 73e788b94b Make min_amt fillable 2017-09-27 14:50:56 -07:00
snipe e91a537552 Use more modern Request handler 2017-09-27 14:50:48 -07:00
snipe ef8c1abf28 Fixes #3113 and #4040 2017-09-27 14:50:17 -07:00
snipe bd0498aa69 Fixes #4016 - signature file missing from history tab 2017-09-27 12:58:08 -07:00
snipe ea45033588 Merge branch 'develop' 2017-09-26 16:03:09 -07:00
snipe 5e1df7049c Make collation and charset for mysql an env variable 2017-09-26 16:02:55 -07:00
snipe e27e1a78c3 Fix for case where a fieldset is assigned to a model, but no fields are assigned 2017-09-26 16:01:23 -07:00
snipe d585a34a26 Prevent users from running this as root/admin user 2017-09-26 13:11:01 -07:00
snipe 4edaba648e Tweaks to upgrade script 2017-09-26 13:05:34 -07:00
snipe 9dca7396f3 Merge branch 'develop' 2017-09-26 11:12:55 -07:00
snipe 4324242475 Bumped version 2017-09-26 11:12:36 -07:00
snipe eca5a05335 Fix forgotten password missing route (???) 2017-09-26 11:08:47 -07:00
snipe aa4d3c3ffb Fix forgotten password missing route (???) 2017-09-26 11:07:47 -07:00
snipe d442feb687 Add @gizzmojr as a contributor 2017-09-25 22:18:25 -07:00
snipe 0a88141b18 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-25 22:17:38 -07:00
snipe d5e6d82ca1 Bumped version 2017-09-25 22:17:00 -07:00
gizzmojr f2a62857cb Clear audit input field (#4010) 2017-09-25 22:15:29 -07:00
snipe b354ca817d Bumped version 2017-09-25 22:10:06 -07:00
snipe 4b9bfc178d One more try on #4001 2017-09-25 22:05:57 -07:00
snipe abc2f7e789 Bumped build number 2017-09-25 21:57:16 -07:00
snipe 29cc9a0815 Tweaks to upgrade script 2017-09-25 21:50:41 -07:00
snipe f2ee7dcabb Fixes #4001 - license checkout not working 2017-09-25 21:40:43 -07:00
snipe 26203801f6 Fixes #4009 - zip not populating on locations listing page 2017-09-25 20:45:05 -07:00
snipe fbe9539130 Proto upgrade script 2017-09-25 20:30:18 -07:00
snipe 43ec959385 Add @richardhofman6 as a contributor 2017-09-25 16:58:47 -07:00
snipe 9b6276f281 Bumped version 2017-09-25 16:04:23 -07:00
snipe 0715791229 Include oauth keys in backup 2017-09-25 15:45:33 -07:00
snipe 0a0661bf41 Additional fixes for #3995 in atypical blades 2017-09-25 15:41:02 -07:00
snipe 6ee939d29b Allegedly fixes #3995 - subdirectory issues with JS/CSS 2017-09-25 15:39:18 -07:00
snipe c3afbc0e53 Run backups before purging and importing 2017-09-25 15:00:23 -07:00
snipe 38326314ca Merge branch 'develop' 2017-09-25 11:53:33 -07:00
snipe 865950e766 Fixes #4000 - user_id blank 2017-09-25 11:53:10 -07:00
snipe d49b67d033 Fix for assigned user location
Was breaking requestable page
2017-09-25 11:26:04 -07:00
snipe 6b63808e34 Fix for asset location null on user 2017-09-25 11:25:15 -07:00
snipe 34dfcb5add Merge branch 'develop' 2017-09-22 17:23:38 -07:00
snipe 30019a144a Disable login note editing on demo 2017-09-22 17:23:22 -07:00
snipe 3e222b674a Merge branch 'develop'
# Conflicts:
#	resources/views/hardware/view.blade.php
2017-09-22 17:04:43 -07:00
snipe e316444c63 Show suppliers link - force cache break? 2017-09-22 17:03:57 -07:00
snipe b29d7beb3a Merge branch 'develop'
# Conflicts:
#	.gitignore
#	Dockerfile
#	README.md
#	app/Http/Controllers/AccessoriesController.php
#	app/Http/Controllers/AssetMaintenancesController.php
#	app/Http/Controllers/AssetsController.php
#	app/Http/Controllers/ConsumablesController.php
#	app/Http/Controllers/GroupsController.php
#	app/Http/Controllers/LicensesController.php
#	app/Http/Controllers/ReportsController.php
#	app/Http/Controllers/UsersController.php
#	app/Http/routes.php
#	app/Models/Depreciation.php
#	app/Models/Location.php
#	config/version.php
#	resources/views/account/view-assets.blade.php
#	resources/views/hardware/edit.blade.php
#	resources/views/hardware/view.blade.php
#	resources/views/partials/modals.blade.php
#	resources/views/reports/custom.blade.php
#	snipeit.sh
2017-09-22 16:12:18 -07:00
snipe f0a49fefd7 Bumped version 2017-09-22 15:50:24 -07:00
snipe 998c4a5fe5 Make model number nullable 2017-09-22 04:43:28 -07:00
snipe 626a6408d0 Additional Danish and Polish translations 2017-09-18 19:12:37 -07:00
snipe 126a5671fe Set timeout for LDAP server 2017-09-18 19:11:38 -07:00
snipe aff104fa5d Bumped version for beta 2017-09-18 18:10:43 -07:00
Daniel Meltzer a5764351f7 Migrate weird assigned_type issues, Issue #3972 (#3973)
For a while, prior to 987536930, we did not null assigned_type on
checkin.  This migration manually nulls all assigned_type fields if
assigned_to is unset.  Add a test to AssetTest for this as well...kind
of.  We need to extract an Asset::checkin() method for 4.1 that mirrors
Asset::checkOut() to really test this.

This also fixes a separate (but related) issue.  The Asset importer did
not set assigned_type when importing and creating users.  In this
instance, we assume that if assigned_to is set and assigned_type is not,
then the item was checked out to a user and update the DB accordingly.
Also add a check in ImporterTest for this issue.
2017-09-18 16:40:13 -07:00
snipe 348becbbec Production assets generated 2017-09-18 13:01:54 -07:00
Daniel Meltzer 922d6937ae Custom field import repair (#3968)
* There is no notes field on accessories.  Fixes Importer Test.

* Fix notification test.  We should see a checkout not allowed exception when trying to check out to a location if the asset requires acceptance.

* Fix Custom field import.

Add a test for custom field import, and fix a few issues related to
importing custom fields.  This will restore v3 functionality.

* Add UI support for mapping custom fields.

This still requires the field mappings to be created/assigned in
advance, but will fetch all custom field names and allow them to be
selected when setting up custom field mappings.

This commit also updates laravel-mix to v1.4.3 and other node
dependencies to fix some build issues.

* Fix some requestable asset page/assetloc issues.  I'd love to know why laravel expections relationships to be in lower case... but thats a question for another day.
2017-09-18 12:29:08 -07:00
snipe c53dae4b72 Possible fix for #3919 - allow later versions of mcrypted base64 keys 2017-09-14 16:43:41 -07:00
snipe 17ad7f7800 Merge branch 'master' of github.com:snipe/snipe-it 2017-09-14 14:14:45 -07:00
snipe 6232a077b5 Fix more enum fuckery 2017-09-14 14:06:53 -07:00
snipe e7d72beb88 Also check for $snipeSettings in the first place
Since the preflight also uses this basic blade
2017-09-12 13:08:43 -07:00
snipe 01e3f4a4db Use site name if provided in the settings table for basic template 2017-09-12 13:01:51 -07:00
snipe 1b76880b0e Add @imanghafoori1 as a contributor 2017-09-12 12:30:21 -07:00
Iman ed4ea7f1f4 No new feature,No bug fix, Only refactoring (#3949)
* No change in logic !

Just exchanging the if and else code blocks and negating condition.

* remove unneeded else{} block

* Re-indented the code
2017-09-12 12:28:42 -07:00
snipe 81e358a01d Small maintenance fixes 2017-09-08 17:49:01 -07:00
snipe 6c283de60a Check for status_id key - related to #3928
TODO: Fix for model number
2017-09-08 17:24:28 -07:00
snipe 4e7a6c0ccf Fixes #3928 - adds correct key generation and passport install 2017-09-08 17:23:19 -07:00
snipe eba145503b Bumped version 2017-09-06 19:02:05 -07:00
snipe ae8c9d6afc Updated translations 2017-09-06 18:05:32 -07:00
snipe faeca4139d Added new languages, commented out ones with 0% translated 2017-09-06 17:51:11 -07:00
snipe 47909b93f7 Fixed deleted users/restore users view 2017-09-06 17:11:43 -07:00
snipe 472658b2fe Fixes #3924 - missing/donked language string 2017-09-06 17:11:23 -07:00
snipe 42a03a0436 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-06 16:25:07 -07:00
Daniel Meltzer ae0573b3da Fix asset create (#3929)
* Fix accidental commit of ImporterTest.

* Move the name() method to the presenter

This fixes some weird collisions between laravels voodoo and our
presenter voodoo that confused php.  It's also probably a cleaner place
to put it.  Should fix #3927

* Add missing parenthesis

* Add heading to tables on locations/view page.
2017-09-06 16:24:43 -07:00
snipe 34f816097e Fixed missing quotation mark 2017-09-06 15:43:07 -07:00
snipe c651c9f1ed Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-09-05 18:35:43 -07:00
snipe 7c390cee2c Bumped version 2017-09-05 18:35:39 -07:00
Daniel Meltzer 987536930c Assorted fixes (#3923)
* Fix some n+1 problems

* Use route in notification dropdown to make sure we link to correct page

* Work on better UI support for checkout to non-user.  Fix links on index bootstrap table, work towards eliminating assignedUser

* Remove Asset::assigneduser() relationship.  Instead add a checkedOutToUser() method and/or port to using assignedTo()

* Adjust string to fit new reality

* Fix #3780.  Move the consumables getDataView method to the ApiController.  Not entirely RESTful, but it's a weird method that probably doesn't need its own controller and the functionality would be strange to stack on the userscontroller...

* Fix file uploads to assets and restore the delete route.

* Add asset maintence edit action to index.

* Suppliers asset list should link to the related asset, not to the supplier with same ID.

* Asset models page should use polymorphic formatter on assigned to to better handle assorted item types.

* Comment out more assigneduser fallacy until we figure out the query builder approach to searching for location text.
2017-09-05 17:54:58 -07:00
snipe 10f322198f Move audited count to top of table 2017-08-31 21:31:07 -07:00
snipe 761371509d Use notifiables for slack audit notification 2017-08-31 21:30:38 -07:00
snipe 3518ea7e7d Fixes #606 - email notifications for expected checkins 2017-08-31 21:18:05 -07:00
snipe c92eed2b3e Small HTML email tweaks 2017-08-31 21:17:02 -07:00
snipe 0054ce3071 Fixes #3907 2017-08-31 13:45:48 -07:00
snipe b0f74466bb Removed dd 2017-08-31 11:15:52 -07:00
snipe b4a0484295 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-08-31 11:15:03 -07:00
Daniel Meltzer bb874012d9 Progress towards better email notifications (#3911)
Working mail from notification.  Still requires testing/cleaning

Add tests around checkout notification.

This also removes the ability to check out an asset to a location|asset
that requires acceptance/a Eula.  For 4.1 we may think about how to
support such a thing, but at present it seems to make sense to only alow
such assets to be checked out to users, who can be responsible for the
items.
2017-08-31 11:14:21 -07:00
snipe bb8583eb14 Remove lower casing for LDAP array re: #3910 2017-08-31 11:00:08 -07:00
snipe 8d2c229bc3 Move LDAP validation into form request 2017-08-31 10:44:00 -07:00
snipe 48e6208214 Fixes #3907 - do not require username on user if LDAP import 2017-08-31 10:43:36 -07:00
snipe 22233e3ba6 Bulk asset audit form (needs more testing) 2017-08-29 16:00:22 -07:00
KeenRivals fd515654ff Fix broken user's manual link (#3902)
snipe-it-manual.readme.io goes to a 404 page
2017-08-29 13:50:57 -07:00
snipe e439f15a64 Fixed some date math for auditing 2017-08-28 17:20:20 -07:00
snipe 42175782a5 Only pull logo if there is a value 2017-08-26 17:43:00 -07:00
snipe c7a21e0e4d Production asset build 2017-08-26 17:39:59 -07:00
snipe d98ffd94f9 Localized modal titles with correct headers 2017-08-26 16:16:41 -07:00
Brady Wetherington 6ad5da44f3 Formalize modals (#3898)
* Refactor Modal JS into standalone file, remove duplicated JS and HTML

* Finish fixing Bulk-checkout and checkout
2017-08-26 16:06:52 -07:00
snipe 479f422e68 Added default if no audit settings are in place 2017-08-26 15:27:50 -07:00
snipe e10cdd57a5 Removed old getassetloist method 2017-08-26 15:22:04 -07:00
snipe bf157773c8 Also related to #3888 2017-08-26 15:21:38 -07:00
snipe fba3949530 Fixes #3888 - broken preview of existing assets 2017-08-26 15:21:10 -07:00
snipe abc3dea8ac Fixed wonky datepicker on bulk checkout 2017-08-26 14:16:16 -07:00
snipe 51d74ac06d Auduting improvements 2017-08-25 18:40:20 -07:00
snipe af835d6efc Additional setting validation for new fields 2017-08-25 17:59:01 -07:00
Robin Temme 5347b19910 Update Maintained Badge (#3877)
The maintenance badge was outdated and displayed "no!". As I guess this was not it's intended purpose, I changed it to the new path, and it now displays "yes".
2017-08-23 12:05:29 -07:00
snipe 29f1cf2b48 Increase depreciation max 2017-07-19 19:41:21 -07:00
Sorvani f56862c684 change CentOS 7 to pull from git (#3734)
The package setup for CentOS 7 already installs git so use it for the install. This makes later updates easier for the end users. They can simply use git pull like the instructions say for updating.
2017-07-11 20:28:31 -07:00
snipe 1052be670d Increase size of state field 2017-06-15 21:04:10 -07:00
Daniel Nemanic 30a9704625 Update UsersController.php (#3640)
If a user is disabled in your Active Directory, it should be deactivated in the licensing too.

The standard state is now deactivated for synced accounts.
Maybe we can change this throw a Setting for a standard state.

The codes comes from this site:
http://www.netvision.com/ad_useraccountcontrol.php
2017-06-12 15:29:55 -07:00
Lee Thoong Ching 9a9b6ae228 Update snipeit.sh (#3620)
To support Oracle Linux ( equivalent to redhat which check os version and type )
2017-06-01 20:54:23 -07:00
morph027 7c8dc9fe2d docker: use ubuntu:xenial with php7.0 (#3616)
Nice, thanks! I'll patch this over to develop as well.
2017-06-01 20:50:09 -07:00
snipe b81dd18576 Fixed delete_at 2017-05-19 03:00:19 -07:00
snipe dac4b58892 Show warning on deleted items 2017-05-19 02:58:55 -07:00
snipe 71fd430f8e Fixes issue with older, deleted asset tags caching QR codes 2017-05-19 02:51:35 -07:00
snipe 5265821bcc Bumped version 2017-05-18 22:24:03 -07:00
snipe cb494a74ca Merge branch 'master' of github.com:snipe/snipe-it 2017-05-18 22:20:57 -07:00
snipe c526ffbf68 Bumped version 2017-05-18 22:20:52 -07:00
snipe 6f5fe83a91 Fixed missing language string in asset display 2017-05-18 22:20:43 -07:00
Nate Felton 5a3816c907 Fixing a regression for RHEL 6 with snipe/snipe-it#2993 (#3572) 2017-05-12 17:19:41 -07:00
snipe c8796cf045 Only prompt for checkin if there is an assigned user 2017-05-10 03:37:30 -07:00
snipe f4095c6dd0 Bumped version 2017-05-09 15:32:34 -07:00
snipe ee2c67a65f Added missing logging back in 2017-05-09 15:30:45 -07:00
snipe 5614578710 Don’t make the item clickable if it’s been deleted 2017-05-09 15:30:19 -07:00
snipe 08ef78356d Update Crowdin configuration file 2017-04-06 20:59:25 -07:00
Manasses Ferreira 47ac59abef We noted that the barcode folder was not being created. (what is done now in the entrypoint.sh) At the same time, a wrong directory was being created. (which explains the deleted line in Dockerfile) (#3456) 2017-03-31 13:48:50 -07:00
snipe 265a896211 Bumped version 2017-02-22 22:38:33 -08:00
snipe f7e4fca70d Add model_number to accessory search 2017-02-22 22:34:56 -08:00
snipe bb4c443cd9 Added notes to custom report 2017-02-03 02:20:56 -08:00
snipe 7b1d2ee050 Fixed typo 2017-01-17 11:57:24 -08:00
snipe b3f70a046f Don’t require superadmin for checkin and delete user 2017-01-17 09:19:14 -08:00
morph027 734e87f85f Installer fine tuning (#2993)
* used shellcheck to lint snipeit.sh

* do not depend on lsb-release command

* add lsb codename

* really use perms()

* more fixes

* quiet apt

* silent logging using log()

* start mysql if not running

* added curl to ubuntu

* added logfile to log function

* update apt index after adding mariadb repo

* fixed typo

* review fixes
2017-01-10 23:07:06 -08:00
snipe f371c5fd62 Merge branch 'master' of github.com:snipe/snipe-it 2017-01-10 19:02:18 -08:00
snipe 4b3edbd2f5 Fixed #3130 - model ID not being saved weith model info on modal for create asset 2017-01-10 19:02:13 -08:00
Byron Wolfman 1f3106b9da Use debian base container and clean up apt-get (#3011)
* Use debian base container and clean up apt-get

Attempt to slim down the docker image by replacing ubuntu:trusty with debian:jessie and clean up after apt-get invocation. Building against the 3.6.0 commit shows a healthy reduction of 44MB, or 9%, compared to the ubuntu-based image.

* Use debian:jessie-slim for an even smaller image

If we're using a debian base image for sizing reasons, we may as well go the full distance and use debian-slim.
2017-01-10 16:22:06 -08:00
snipe 9fd3a9a82d Removed logging 2017-01-06 03:12:49 -08:00
snipe a6e6991a2d Removed second number_format 2017-01-06 03:11:27 -08:00
snipe 93ba0717d8 Removed number_format 2017-01-06 03:02:38 -08:00
snipe a8839e0ef4 Fixes #3104, #2914 and #2918 - auto-increment incorrectly generating next ID 2017-01-06 02:52:10 -08:00
snipe 3e4152c966 Bumped version 2017-01-06 00:04:26 -08:00
snipe 1bf34d73f5 Use correct authorize rule in middleware for user delete 2017-01-06 00:02:46 -08:00
snipe d1e360d64d Fix logic to use gate instead of asking if superuser 2017-01-06 00:02:19 -08:00
snipe 3b5b19848c Added oauth keys to gitignore 2017-01-06 00:01:55 -08:00
snipe 93ba90e837 Merge remote-tracking branch 'origin/develop' 2016-12-12 19:24:00 -08:00
snipe fc70d79a17 Merge remote-tracking branch 'origin/develop' 2016-12-12 19:07:07 -08:00
snipe 65016a2383 Merge remote-tracking branch 'origin/develop' 2016-12-05 16:12:41 -08:00
snipe dbcb2ccb46 Merge remote-tracking branch 'origin/develop' 2016-12-05 15:09:49 -08:00
snipe 2afcfcc87c Set DB_SSL to false for config 2016-12-03 17:32:44 -08:00
snipe 1afef9416a Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	config/version.php
2016-12-03 17:15:02 -08:00
snipe 4049143ebf Bumped version 2016-12-01 06:11:03 -08:00
snipe 4df53bdf8d Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	config/version.php
#	resources/views/account/view-assets.blade.php
2016-12-01 06:10:50 -08:00
snipe d49a1ea304 More graceful error message if log doesn’t exist 2016-12-01 06:05:14 -08:00
snipe 521f4facd5 Bumped version 2016-12-01 05:56:24 -08:00
snipe b4653dfc15 Ignore npm log 2016-12-01 05:55:29 -08:00
1749 changed files with 31469 additions and 20050 deletions
+54
View File
@@ -728,6 +728,60 @@
"contributions": [
"code"
]
},
{
"login": "imanghafoori1",
"name": "Iman",
"avatar_url": "https://avatars0.githubusercontent.com/u/6961695?v=4",
"profile": "https://github.com/imanghafoori1",
"contributions": [
"code"
]
},
{
"login": "richardhofman6",
"name": "Richard Hofman",
"avatar_url": "https://avatars1.githubusercontent.com/u/6551003?v=4",
"profile": "https://github.com/richardhofman6",
"contributions": [
"code"
]
},
{
"login": "gizzmojr",
"name": "gizzmojr",
"avatar_url": "https://avatars0.githubusercontent.com/u/3697569?v=4",
"profile": "https://github.com/gizzmojr",
"contributions": [
"code"
]
},
{
"login": "imjennyli",
"name": "Jenny Li",
"avatar_url": "https://avatars3.githubusercontent.com/u/404729?v=4",
"profile": "https://github.com/imjennyli",
"contributions": [
"doc"
]
},
{
"login": "GeoffYoung",
"name": "Geoff Young",
"avatar_url": "https://avatars0.githubusercontent.com/u/869227?v=4",
"profile": "https://github.com/GeoffYoung",
"contributions": [
"code"
]
},
{
"login": "BlueHatbRit",
"name": "Elliot Blackburn",
"avatar_url": "https://avatars3.githubusercontent.com/u/1068477?v=4",
"profile": "http://www.elliotblackburn.com",
"contributions": [
"doc"
]
}
]
}
+15 -5
View File
@@ -8,7 +8,6 @@ APP_URL=null
APP_TIMEZONE='UTC'
APP_LOCALE=en
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
@@ -19,6 +18,8 @@ DB_USERNAME=null
DB_PASSWORD=null
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS
@@ -29,7 +30,6 @@ DB_SSL_CERT_PATH=null
DB_SSL_CA_PATH=null
DB_SSL_CIPHER=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
@@ -44,14 +44,12 @@ MAIL_FROM_NAME='Snipe-IT'
MAIL_REPLYTO_ADDR=you@example.com
MAIL_REPLYTO_NAME='Snipe-IT'
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
# This should be gd or imagick
# --------------------------------------------
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
@@ -62,6 +60,11 @@ COOKIE_NAME=snipeit_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: SECURITY HEADER SETTINGS
# --------------------------------------------
REFERRER_POLICY=same-origin
ENABLE_CSP=false
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
@@ -70,6 +73,12 @@ CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: REDIS SETTINGS
# --------------------------------------------
REDIS_HOST=null
REDIS_PASSWORD=null
REDIS_PORT-null
# --------------------------------------------
# OPTIONAL: AWS S3 SETTINGS
@@ -88,7 +97,8 @@ LOGIN_LOCKOUT_DURATION=60
# --------------------------------------------
# OPTIONAL: MISC
# --------------------------------------------
APP_LOG=single
APP_LOG=daily
APP_LOG_MAX_FILES=10
APP_LOCKED=false
FILESYSTEM_DISK=local
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
+10 -3
View File
@@ -12,20 +12,27 @@
#### Please confirm you have done the following before posting your bug report:
- [ ] I have enabled debug mode
- [ ] I have enabled debug mode
- [ ] I have read [checked the Common Issues page](https://snipe-it.readme.io/docs/common-issues)
-----
#### Please provide answers to these questions before posting your bug report:
#### Provide answers to these questions:
- Is this a fresh install or an upgrade?
- Version of Snipe-IT you're running
- Version of PHP you're running
- Version of MySQL/MariaDB you're running
- What OS and web server you're running Snipe-IT on
- What method you used to install Snipe-IT (install.sh, manual installation, docker, etc)
- WITH DEBUG TURNED ON, if you're getting an error in your browser, include that error
- 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).
- 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.
- 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
Please do not post an issue without answering the related questions above. If you have opened a different issue and already answered these questions, answer them again, once for every ticket. It will be next to impossible for us to help you.
https://snipe-it.readme.io/docs/getting-help
+1 -1
View File
@@ -43,7 +43,7 @@ before_script:
# use the $DB env variable to determine the phpunit.xml to use
# script: ./vendor/bin/codecept run --env testing-ci
script:
- ./vendor/bin/codecept run unit --env testing-ci
- ./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
+1 -1
View File
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
reported by contacting the project team at abuse@snipeitapp.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
+1 -1
View File
@@ -1,6 +1,6 @@
### Contributing
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing).
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview).
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
+4 -4
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.png)](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://raw.githubusercontent.com/ZenHubIO/support/master/zenhub-badge.png)](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-78-orange.svg?style=flat-square)](#contributors)
[![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-84-orange.svg?style=flat-square)](#contributors)
## Snipe-IT - Open Source Asset Management System
@@ -67,7 +67,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars0.githubusercontent.com/u/8341172?v=3" width="110px;"/><br /><sub>Jay Richards</sub>](http://www.cordeos.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=technogenus "Code") | [<img src="https://avatars2.githubusercontent.com/u/7295127?v=3" width="110px;"/><br /><sub>Alexander Innes</sub>](https://necurity.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leostat "Code") | [<img src="https://avatars2.githubusercontent.com/u/334485?v=3" width="110px;"/><br /><sub>Danny Garcia</sub>](https://buzzedword.codes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=buzzedword "Code") | [<img src="https://avatars2.githubusercontent.com/u/366855?v=3" width="110px;"/><br /><sub>archpoint</sub>](https://github.com/archpoint)<br />[💻](https://github.com/snipe/snipe-it/commits?author=archpoint "Code") | [<img src="https://avatars1.githubusercontent.com/u/67991?v=3" width="110px;"/><br /><sub>Jake McGraw</sub>](http://www.jakemcgraw.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jakemcgraw "Code") | [<img src="https://avatars1.githubusercontent.com/u/1714374?v=3" width="110px;"/><br /><sub>FleischKarussel</sub>](https://github.com/FleischKarussel)<br />[📖](https://github.com/snipe/snipe-it/commits?author=FleischKarussel "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/319644?v=3" width="110px;"/><br /><sub>Dylan Yi</sub>](https://github.com/feeva)<br />[💻](https://github.com/snipe/snipe-it/commits?author=feeva "Code") |
| [<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://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") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -76,7 +76,7 @@ This project follows the [all-contributors](https://github.com/kentcdodds/all-co
### Contributing
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing).
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing-overview).
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
+33 -20
View File
@@ -16,7 +16,7 @@ class LdapSync extends Command
*
* @var string
*/
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--summary}';
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--summary} {--json_summary}';
/**
* The console command description.
@@ -55,27 +55,35 @@ class LdapSync extends Command
try {
$ldapconn = Ldap::connectToLdap();
} catch (\Exception $e) {
LOG::error($e);
}
try {
Ldap::bindAdminToLdap($ldapconn);
} 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 [];
}
$summary = array();
$results = Ldap::findLdapUsers();
$ldap_ou_locations = Location::whereNotNull('ldap_ou')->get();
// 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.');
}
$results = Ldap::findLdapUsers();
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
@@ -90,8 +98,8 @@ class LdapSync extends Command
LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
} else {
$location = NULL;
}
$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.');
@@ -99,11 +107,11 @@ class LdapSync extends Command
// 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);
$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;
$location_users[$i]["location_id"] = $ldap_loc["id"];
$usernames[] = $location_users[$i][$ldap_result_username][0];
}
@@ -135,6 +143,14 @@ class LdapSync extends Command
$item["ldap_location_override"] = isset($results[$i]["ldap_location_override"]) ? $results[$i]["ldap_location_override"]:"";
$item["location_id"] = isset($results[$i]["location_id"]) ? $results[$i]["location_id"]:"";
if ( array_key_exists('useraccountcontrol', $results[$i]) ) {
$enabled_accounts = [
'512', '544', '66048', '66080', '262656', '262688', '328192', '328224'
];
$item['activated'] = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
} else {
$item['activated'] = 0;
}
// User exists
$item["createorupdate"] = 'updated';
@@ -145,14 +161,12 @@ class LdapSync extends Command
}
// Create the user if they don't exist.
$user->first_name = e($item["firstname"]);
$user->last_name = e($item["lastname"]);
$user->username = e($item["username"]);
$user->email = e($item["email"]);
$user->employee_num = e($item["employee_number"]);
$user->activated = 1;
$user->activated = $item['activated'];
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
@@ -188,13 +202,12 @@ class LdapSync extends Command
} else {
$this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].' was '.strtoupper($summary[$x]['createorupdate']).'.');
}
}
} else if ($this->option('json_summary')) {
$json_summary = [ "error" => false, "error_message" => "", "summary" => $summary ];
$this->info(json_encode($json_summary));
} else {
return $summary;
}
}
}
+1 -6
View File
@@ -78,12 +78,7 @@ class ObjectImportCommand extends Command
$logFile = $this->option('logfile');
\Log::useFiles($logFile);
if ($this->option('testrun')) {
$this->comment('====== TEST ONLY Item Import for '.$filename.' ====');
$this->comment('============== NO DATA WILL BE WRITTEN ==============');
} else {
$this->comment('======= Importing Items from '.$filename.' =========');
}
$this->comment('======= Importing Items from '.$filename.' =========');
$importer->import();
$this->bar = null;
+16 -3
View File
@@ -47,6 +47,7 @@ class RecryptFromMcrypt extends Command
// Check and see if they have a legacy app key listed in their .env
// If not, we can try to use the current APP_KEY if looks like it's old
$legacy_key = env('LEGACY_APP_KEY');
$key_parts = explode(':', $legacy_key);
$errors = array();
if (!$legacy_key) {
@@ -54,11 +55,23 @@ class RecryptFromMcrypt extends Command
return false;
}
// Check that the app key is 32 characters
// Do some basic legacy app key length checks
if (strlen($legacy_key) == 32) {
$this->comment('INFO: Your LEGACY_APP_KEY is 32 characters. Okay to continue.');
$legacy_length_check = true;
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1])==44)) {
$legacy_length_check = true;
} else {
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
$legacy_length_check = false;
}
// Check that the app key is 32 characters
if ($legacy_length_check === true) {
$this->comment('INFO: Your LEGACY_APP_KEY looks correct. Okay to continue.');
} else {
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters or base64 followed by 44 characters for later versions). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
return false;
}
@@ -0,0 +1,75 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Setting;
use App\Models\User;
class ResetDemoSettings extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:demo-settings';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This will reset the Snipe-IT demo settings back to default. ';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Resetting the demo settings.');
$settings = Setting::first();
$settings->per_page = 20;
$settings->site_name = 'Snipe-IT Asset Management Demo';
$settings->auto_increment_assets = 1;
$settings->logo = 'snipe-logo.png';
$settings->alert_email = 'service@snipe-it.io';
$settings->header_color = null;
$settings->barcode_type = 'QRCODE';
$settings->default_currency = 'USD';
$settings->brand = 3;
$settings->ldap_enabled = 0;
$settings->full_multiple_companies_support = 1;
$settings->alt_barcode = 'C128';
$settings->email_domain = 'snipeitapp.com';
$settings->email_format = 'filastname';
$settings->username_format = 'filastname';
$settings->date_display_format = 'D M d, Y';
$settings->time_display_format = 'g:iA';
$settings->thumbnail_max_h = '30';
$settings->locale = 'en';
$settings->save();
if ($user = User::where('username', '=', 'admin')->first()) {
$user->locale = 'en';
$user->save();
}
}
}
@@ -0,0 +1,64 @@
<?php
namespace App\Console\Commands;
use App\Models\Asset;
use Illuminate\Console\Command;
use App\Notifications\ExpectedCheckinNotification;
use Carbon\Carbon;
class SendExpectedCheckinAlerts extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:expected-checkin';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Check for overdue or upcoming expected checkins.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$whenNotify = Carbon::now()->addDays(7);
$assets = Asset::with('assignedTo')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
$this->info($whenNotify.' is deadline');
$this->info($assets->count().' assets');
foreach ($assets as $asset) {
if ($asset->assignedTo && $asset->checkoutOutToUser()) {
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
//$this->info($asset);
}
}
}
}
+4 -1
View File
@@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
Commands\CreateAdmin::class,
Commands\SendExpirationAlerts::class,
Commands\SendInventoryAlerts::class,
Commands\SendExpectedCheckinAlerts::class,
Commands\ObjectImportCommand::class,
Commands\Versioning::class,
Commands\SystemBackup::class,
@@ -24,7 +25,8 @@ class Kernel extends ConsoleKernel
Commands\Purge::class,
Commands\LdapSync::class,
Commands\FixDoubleEscape::class,
Commands\RecryptFromMcrypt::class
Commands\RecryptFromMcrypt::class,
Commands\ResetDemoSettings::class
];
/**
@@ -38,6 +40,7 @@ class Kernel extends ConsoleKernel
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
}
+12
View File
@@ -0,0 +1,12 @@
<?php
namespace App\Exceptions;
use Exception;
class CheckoutNotAllowed extends Exception
{
public function __toString()
{
"A checkout is not allowed under these circumstances";
}
}
+5 -1
View File
@@ -7,6 +7,7 @@ use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Helpers\Helper;
use Illuminate\Validation\ValidationException;
use Log;
class Handler extends ExceptionHandler
{
@@ -34,7 +35,10 @@ class Handler extends ExceptionHandler
*/
public function report(Exception $exception)
{
parent::report($exception);
if ($this->shouldReport($exception)) {
Log::error($exception);
return parent::report($exception);
}
}
/**
+3 -141
View File
@@ -260,7 +260,7 @@ class AccessoriesController extends Controller
'assigned_to' => $request->get('assigned_to')
]);
$logaction = $accessory->logCheckout(e(Input::get('note')));
$logaction = $accessory->logCheckout(e(Input::get('note')), $user);
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
@@ -274,7 +274,7 @@ class AccessoriesController extends Controller
$data['note'] = $logaction->note;
$data['require_acceptance'] = $accessory->requireAcceptance();
// TODO: Port this to new mail notifications
if (($accessory->requireAcceptance()=='1') || ($accessory->getEula())) {
if ((($accessory->requireAcceptance()=='1') || ($accessory->getEula())) && ($user->email!='')) {
Mail::send('emails.accept-accessory', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
@@ -351,7 +351,7 @@ class AccessoriesController extends Controller
$data['item_tag'] = '';
$data['note'] = e($logaction->note);
if (($accessory->checkin_email()=='1')) {
if ((($accessory->checkin_email()=='1')) && ($user->email!='')) {
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
@@ -369,143 +369,5 @@ class AccessoriesController extends Controller
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error'));
}
/**
* Generates the JSON response for accessories listing view.
*
* Example:
* {
* "actions": "(links to available actions)",
* "category": "(link to category)",
* "company": "My Company",
* "location": "My Location",
* "min_amt": 2,
* "name": "(link to accessory),
* "numRemaining": 6,
* "order_number": null,
* "purchase_cost": "0.00",
* "purchase_date": null,
* "qty": 7
* },
*
* The names of the fields in the returns JSON correspond directly to the the
* names of the fields in the bootstrap-tables in the view.
*
* For debugging, see at /api/accessories/list
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @return string JSON containing accessories and their associated atrributes.
* @internal param int $accessoryId
*/
public function getDatatable(Request $request)
{
$this->authorize('index', Accessory::class);
$accessories = Company::scopeCompanyables(
Accessory::select('accessories.*')
->whereNull('accessories.deleted_at')
->with('category', 'company', 'manufacturer', 'users', 'location')
);
if (Input::has('search')) {
$accessories = $accessories->TextSearch(e(Input::get('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['name','min_amt','order_number','purchase_date','purchase_cost','company','category','model_number', 'manufacturer', 'location'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e(Input::get('sort')) : 'created_at';
switch ($sort) {
case 'category':
$accessories = $accessories->OrderCategory($order);
break;
case 'company':
$accessories = $accessories->OrderCompany($order);
break;
case 'location':
$accessories = $accessories->OrderLocation($order);
break;
case 'manufacturer':
$accessories = $accessories->OrderManufacturer($order);
break;
default:
$accessories = $accessories->orderBy($sort, $order);
break;
}
$accessCount = $accessories->count();
$accessories = $accessories->skip($offset)->take($limit)->get();
$rows = array();
foreach ($accessories as $accessory) {
$rows[] = $accessory->present()->forDataTable();
}
$data = array('total'=>$accessCount, 'rows'=>$rows);
return $data;
}
/**
* Generates the JSON response for accessory detail view.
*
* Example:
* <code>
* {
* "rows": [
* {
* "actions": "(link to available actions)",
* "name": "(link to user)"
* }
* ],
* "total": 1
* }
* </code>
*
* The names of the fields in the returns JSON correspond directly to the the
* names of the fields in the bootstrap-tables in the view.
*
* For debugging, see at /api/accessories/$accessoryID/view
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return string JSON containing accessories and their associated atrributes.
**/
public function getDataView(Request $request, $accessoryID)
{
$accessory = Accessory::find($accessoryID);
if (!Company::isCurrentUserHasAccess($accessory)) {
return ['total' => 0, 'rows' => []];
}
$accessory_users = $accessory->users;
$count = $accessory_users->count();
$rows = array();
foreach ($accessory_users as $user) {
$actions = '';
if (Gate::allows('checkin', $accessory)) {
$actions .= Helper::generateDatatableButton('checkin', route('checkin/accessory', $user->pivot->id));
}
if (Gate::allows('view', $user)) {
$name = (string) link_to_route('users.show', e($user->present()->fullName()), [$user->id]);
} else {
$name = e($user->present()->fullName());
}
$rows[] = array(
'name' => $name,
'actions' => $actions
);
}
$data = array('total'=>$count, 'rows'=>$rows);
return $data;
}
}
@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Accessory;
use App\Http\Transformers\AccessoriesTransformer;
use App\Models\Company;
class AccessoriesController extends Controller
@@ -128,10 +129,15 @@ class AccessoriesController extends Controller
public function checkedout($id)
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::findOrFail($id)->with('users')->first();
$accessories_users = $accessory->users;
$total = $accessories_users->count();
return (new AccessoriesTransformer)->transformCheckedoutAccessories($accessories_users, $total);
$accessory = Accessory::findOrFail($id);
if (!Company::isCurrentUserHasAccess($accessory)) {
return ['total' => 0, 'rows' => []];
}
$accessory_users = $accessory->users;
$total = $accessory_users->count();
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory_users, $total);
}
@@ -1,16 +1,17 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\AssetMaintenance;
use Carbon\Carbon;
use App\Models\Company;
use App\Models\Asset;
use App\Helpers\Helper;
use Auth;
use Gate;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Transformers\AssetMaintenancesTransformer;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use App\Models\Company;
use Auth;
use Carbon\Carbon;
use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
/**
* This controller handles all actions related to Asset Maintenance for
@@ -31,7 +31,7 @@ class AssetModelsController extends Controller
$this->authorize('view', AssetModel::class);
$allowed_columns = ['id','image','name','model_number','eol','notes','created_at','manufacturer'];
$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'])
$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'])
->with('category','depreciation', 'manufacturer','fieldset')
->withCount('assets');
@@ -39,6 +39,10 @@ class AssetModelsController extends Controller
$assetmodels->TextSearch($request->input('search'));
}
if ($request->has('status')) {
$assetmodels->onlyTrashed();
}
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
+78 -21
View File
@@ -84,9 +84,8 @@ class AssetsController extends Controller
}
$assets = Company::scopeCompanyables(Asset::select('assets.*'))->with(
'assetLoc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
'model.category', 'model.manufacturer', 'model.fieldset', 'assigneduser','supplier');
'assetloc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
// If we should search on everything
if (($request->has('search')) && (count($filter) == 0)) {
$assets->TextSearch($request->input('search'));
@@ -97,7 +96,6 @@ class AssetsController extends Controller
}
}
// These are used by the API to query against specific ID numbers
if ($request->has('status_id')) {
$assets->where('status_id', '=', $request->input('status_id'));
@@ -127,7 +125,11 @@ class AssetsController extends Controller
$assets->ByManufacturer($request->input('manufacturer_id'));
}
$request->has('order_number') ? $assets = $assets->where('order_number', '=', e($request->get('order_number'))) : '';
if ($request->has('depreciation_id')) {
$assets->ByDepreciationId($request->input('depreciation_id'));
}
$request->has('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
$offset = request('offset', 0);
$limit = $request->input('limit', 50);
@@ -135,28 +137,62 @@ class AssetsController extends Controller
// This is used by the sidenav, mostly
// We switched from using query scopes here because of a Laravel bug
// related to fulltext searches on complex queries.
// I am sad. :(
switch ($request->input('status')) {
case 'Deleted':
$assets->withTrashed()->Deleted();
break;
case 'Pending':
$assets->Pending();
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',0)
->where('status_alias.pending','=',1)
->where('status_alias.archived', '=', 0);
});
break;
case 'RTD':
$assets->RTD();
$assets->whereNull('assets.assigned_to')
->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',1)
->where('status_alias.pending','=',0)
->where('status_alias.archived', '=', 0);
});
break;
case 'Undeployable':
$assets->Undeployable();
break;
case 'Archived':
$assets->Archived();
$assets->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',0)
->where('status_alias.pending','=',0)
->where('status_alias.archived', '=', 1);
});
break;
case 'Requestable':
$assets->RequestableAssets();
$assets->where('assets.requestable', '=', 1)
->join('status_labels AS status_alias',function ($join) {
$join->on('status_alias.id', "=", "assets.status_id")
->where('status_alias.deployable','=',1)
->where('status_alias.pending','=',0)
->where('status_alias.archived', '=', 0);
});
break;
case 'Deployed':
$assets->Deployed();
// more sad, horrible workarounds for laravel bugs when doing full text searches
$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);
});
}
@@ -483,6 +519,9 @@ class AssetsController extends Controller
$data['item_tag'] = $asset->asset_tag;
$data['item_serial'] = $asset->serial;
$data['note'] = $logaction->note;
$data['manufacturer_name'] = $asset->model->manufacturer->name;
$data['model_name'] = $asset->model->name;
$data['model_number'] = $asset->model->model_number;
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!config('app.lock_passwords'))) {
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
@@ -507,23 +546,41 @@ class AssetsController extends Controller
* @since [v4.0]
* @return JsonResponse
*/
public function audit(Request $request, $id) {
public function audit(Request $request) {
$this->authorize('audit', Asset::class);
$rules = array(
'id' => 'required'
'asset_tag' => 'required',
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable'
);
$validator = \Validator::make($request->all(), $rules);
$asset = Asset::findOrFail($id);
$asset->next_audit_date = $request->input('next_audit_date');
if ($asset->save()) {
$asset->logAudit(request('note'));
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.audit.success')));
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
}
$asset = Asset::where('asset_tag','=', $request->input('asset_tag'))->first();
if ($asset) {
$asset->next_audit_date = $request->input('next_audit_date');
if ($asset->save()) {
$log = $asset->logAudit(request('note'),request('location_id'));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag'=> e($asset->asset_tag),
'note'=> e($request->input('note')),
'next_audit_date' => Helper::getFormattedDateObject($log->calcNextAuditDate())
], trans('admin/hardware/message.audit.success')));
}
}
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.$request->input('asset_tag').' not found'));
}
}
@@ -20,9 +20,9 @@ class CategoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Category::class);
$allowed_columns = ['id', 'name','category_type','use_default_eula','require_acceptance','checkin_email'];
$allowed_columns = ['id', 'name','category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email'];
$categories = Category::select(['id', 'created_at', 'updated_at', 'name','category_type','use_default_eula','require_acceptance','checkin_email'])
$categories = Category::select(['id', 'created_at', 'updated_at', 'name','category_type','use_default_eula','eula_text', 'require_acceptance','checkin_email'])
->withCount('assets', 'accessories', 'consumables', 'components');
if ($request->has('search')) {
@@ -158,6 +158,6 @@ class ComponentsController extends Controller
$limit = $request->input('limit', 50);
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
return (new ComponentsAssetsTransformer)->transformAssets($assets, $total);
return (new ComponentsTransformer)->transformCheckedoutComponents($assets, $total);
}
}
@@ -148,4 +148,47 @@ class ConsumablesController extends Controller
$consumable->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success')));
}
/**
* Returns a JSON response containing details on the users associated with this consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getView() method that returns the form.
* @since [v1.0]
* @param int $consumableId
* @return array
*/
public function getDataView($consumableId)
{
//$consumable = Consumable::find($consumableID);
$consumable = Consumable::with(array('consumableAssignments'=>
function ($query) {
$query->orderBy('created_at', 'DESC');
},
'consumableAssignments.admin'=> function ($query) {
},
'consumableAssignments.user'=> function ($query) {
},
))->find($consumableId);
// $consumable->load('consumableAssignments.admin','consumableAssignments.user');
if (!Company::isCurrentUserHasAccess($consumable)) {
return ['total' => 0, 'rows' => []];
}
$this->authorize('view', Component::class);
$rows = array();
foreach ($consumable->consumableAssignments as $consumable_assignment) {
$rows[] = [
'name' => $consumable_assignment->user->present()->nameUrl(),
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
];
}
$consumableCount = $consumable->users->count();
$data = array('total' => $consumableCount, 'rows' => $rows);
return $data;
}
}
@@ -2,9 +2,11 @@
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Transformers\CustomFieldsTransformer;
use App\Models\CustomField;
use App\Models\CustomFieldset;
use Illuminate\Http\Request;
class CustomFieldsController extends Controller
{
@@ -16,6 +18,15 @@ class CustomFieldsController extends Controller
* @since [v3.0]
* @return Array
*/
public function index()
{
$this->authorize('index', CustomFields::class);
$fields = CustomField::get();
$total = count($fields);
return (new CustomFieldsTransformer)->transformCustomFields($fields, $total);
}
public function postReorder(Request $request, $id)
{
$fieldset = CustomFieldset::find($id);
@@ -73,7 +73,7 @@ class GroupsController extends Controller
{
$this->authorize('view', Group::class);
$group = Group::findOrFail($id);
return $group;
return (new GroupsTransformer)->transformGroup($group);
}
@@ -13,6 +13,7 @@ use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Session;
use League\Csv\Reader;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Artisan;
class ImportController extends Controller
{
@@ -94,6 +95,8 @@ class ImportController extends Controller
public function process(ItemImportRequest $request, $import_id)
{
$this->authorize('create', Asset::class);
// Run a backup immediately before processing
Artisan::call('backup:run');
$errors = $request->import(Import::find($import_id));
$redirectTo = "hardware.index";
switch ($request->get('import-type')) {
@@ -21,7 +21,7 @@ class LicensesController extends Controller
public function index(Request $request)
{
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer'));
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer', 'supplier'));
if ($request->has('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
@@ -23,7 +23,7 @@ class LocationsController extends Controller
$allowed_columns = ['id','name','address','address2','city','state','country','zip','created_at',
'updated_at','parent_id', 'manager_id'];
$locations = Location::select([
$locations = Location::with('parent', 'manager', 'childLocations')->select([
'locations.id',
'locations.name',
'locations.address',
@@ -37,7 +37,10 @@ class LocationsController extends Controller
'locations.created_at',
'locations.updated_at',
'locations.currency'
])->withCount('assets')->withCount('users');
])->withCount('locationAssets')
->withCount('assignedAssets')
->withCount('assets')
->withCount('users');
if ($request->has('search')) {
$locations = $locations->TextSearch($request->input('search'));
@@ -52,7 +55,6 @@ class LocationsController extends Controller
$total = $locations->count();
$locations = $locations->skip($offset)->take($limit)->get();
return (new LocationsTransformer)->transformLocations($locations, $total);
}
@@ -74,7 +76,6 @@ class LocationsController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', (new LocationsTransformer)->transformLocation($location), trans('admin/locations/message.create.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
}
/**
@@ -109,7 +110,13 @@ class LocationsController extends Controller
$location->fill($request->all());
if ($location->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new LocationsTransformer)->transformLocation($location), trans('admin/locations/message.update.success')));
return response()->json(
Helper::formatStandardApiResponse(
'success',
(new LocationsTransformer)->transformLocation($location),
trans('admin/locations/message.update.success')
)
);
}
return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors()));
@@ -129,7 +136,6 @@ class LocationsController extends Controller
$location = Location::findOrFail($id);
$this->authorize('delete', $location);
$location->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success')));
}
}
@@ -19,7 +19,7 @@ class ReportsController extends Controller
public function index(Request $request)
{
$actionlogs = Actionlog::with('item', 'user', 'target');
$actionlogs = Actionlog::with('item', 'user', 'target','location');
if ($request->has('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Ldap;
use Validator;
use App\Models\Setting;
class SettingsController extends Controller
{
@@ -75,8 +77,14 @@ class SettingsController extends Controller
//
}
public function getLdapTest()
public function ldaptest()
{
if (Setting::getSettings()->ldap_enabled!='1') {
\Log::debug('LDAP is not enabled cannot test.');
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
}
\Log::debug('Preparing to test LDAP connection');
try {
@@ -98,4 +106,58 @@ class SettingsController extends Controller
}
public function ldaptestlogin(Request $request)
{
if (Setting::getSettings()->ldap_enabled!='1') {
\Log::debug('LDAP is not enabled. Cannot test.');
return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400);
}
$rules = array(
'ldaptest_user' => 'required',
'ldaptest_password' => 'required'
);
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
\Log::debug('LDAP Validation test failed.');
$validation_errors = implode(' ',$validator->errors()->all());
return response()->json(['message' => $validator->errors()->all()], 400);
}
\Log::debug('Preparing to test LDAP login');
try {
$connection = Ldap::connectToLdap();
try {
Ldap::bindAdminToLdap($connection);
\Log::debug('Attempting to bind to LDAP for LDAP test');
try {
$ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password'));
if ($ldap_user) {
\Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.');
return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200);
}
return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400);
} catch (\Exception $e) {
\Log::debug('LDAP login failed');
return response()->json(['message' => $e->getMessage()], 400);
}
} catch (\Exception $e) {
\Log::debug('Bind failed');
return response()->json(['message' => $e->getMessage()], 400);
//return response()->json(['message' => $e->getMessage()], 500);
}
} catch (\Exception $e) {
\Log::debug('Connection failed');
return response()->json(['message' => $e->getMessage()], 500);
}
}
}
@@ -155,7 +155,7 @@ class StatuslabelsController extends Controller
public function getAssetCountByStatuslabel()
{
$statusLabels = Statuslabel::with('assets')->get();
$statusLabels = Statuslabel::get();
$labels=[];
$points=[];
$colors=[];
@@ -168,9 +168,7 @@ class StatuslabelsController extends Controller
}
}
}
$labels[]='Deployed';
$points[]=Asset::whereNotNull('assigned_to')->count();
$colors_array = array_merge($colors, Helper::chartColors());
$result= [
@@ -9,6 +9,7 @@ use App\Models\Company;
use App\Models\User;
use App\Helpers\Helper;
use App\Http\Requests\SaveUserRequest;
use App\Models\Asset;
class UsersController extends Controller
{
@@ -51,6 +52,11 @@ class UsersController extends Controller
$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'));
}
@@ -58,6 +64,10 @@ class UsersController extends Controller
if ($request->has('location_id')) {
$users = $users->where('location_id', '=', $request->input('location_id'));
}
if ($request->has('group_id')) {
$users = $users->ByGroup($request->has('group_id'));
}
if ($request->has('department_id')) {
$users = $users->where('department_id','=',$request->input('department_id'));
@@ -182,4 +192,19 @@ class UsersController extends Controller
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
}
/**
* Return JSON containing a list of assets assigned to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $userId
* @return string JSON
*/
public function assets($id)
{
$this->authorize('view', User::class);
$assets = Asset::where('assigned_to', '=', $id)->with('model')->get();
return response()->json($assets);
}
}
+29 -58
View File
@@ -17,6 +17,7 @@ use App\Models\Company;
use Config;
use App\Helpers\Helper;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -68,7 +69,7 @@ class AssetModelsController extends Controller
* @since [v1.0]
* @return Redirect
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
// Create a new asset model
@@ -82,7 +83,7 @@ class AssetModelsController extends Controller
$model->manufacturer_id = $request->input('manufacturer_id');
$model->category_id = $request->input('category_id');
$model->notes = $request->input('notes');
$model->user_id = Auth::guard('api')->user();
$model->user_id = Auth::id();
$model->requestable = Input::has('requestable');
if ($request->input('custom_fieldset')!='') {
@@ -90,14 +91,21 @@ class AssetModelsController extends Controller
}
if (Input::file('image')) {
$image = Input::file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/models/'.$file_name);
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$file_name = str_random(25) . "." . $image->getClientOriginalExtension();
$path = public_path('uploads/models/');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
$model->image = $file_name;
}
// Was it created?
@@ -180,7 +188,7 @@ class AssetModelsController extends Controller
* @param int $modelId
* @return Redirect
*/
public function update(Request $request, $modelId = null)
public function update(ImageUploadRequest $request, $modelId = null)
{
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
@@ -206,13 +214,19 @@ class AssetModelsController extends Controller
if (Input::file('image')) {
$image = Input::file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/models/'.$file_name);
Image::make($image->getRealPath())->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$file_name = str_random(25) . "." . $image->getClientOriginalExtension();
$path = public_path('uploads/models/');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(500, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
$model->image = $file_name;
}
if ($request->input('image_delete') == 1 && Input::file('image') == "") {
@@ -352,49 +366,6 @@ class AssetModelsController extends Controller
/**
* Get the asset information to present to the model view detail page
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @param Request $request
* @param $modelID
* @return String JSON
* @internal param int $modelId
*/
public function getDataView(Request $request, $modelID)
{
$assets = Asset::where('model_id', '=', $modelID)->with('company', 'assetstatus');
if (Input::has('search')) {
$assets = $assets->TextSearch(e($request->input('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['name', 'serial','asset_tag'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$assets = $assets->orderBy($sort, $order);
$assetsCount = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
$rows = array();
$all_custom_fields = CustomField::all();
foreach ($assets as $asset) {
$rows[] = $asset->present()->forDataTable($all_custom_fields);
}
$data = array('total' => $assetsCount, 'rows' => $rows);
return $data;
}
/**
* Returns a view that allows the user to bulk edit model attrbutes
+78 -85
View File
@@ -75,7 +75,7 @@ class AssetsController extends Controller
} else {
$company = null;
}
return view('hardware/index')->with('company',$company);
return view('hardware/index')->with('company', $company);
}
/**
@@ -94,7 +94,6 @@ class AssetsController extends Controller
}
$this->authorize('view', $asset);
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
}
/**
@@ -126,9 +125,7 @@ class AssetsController extends Controller
if ($request->has('model_id')) {
$selected_model = AssetModel::find($request->input('model_id'));
$view->with('selected_model', $selected_model);
} else {
}
return $view;
}
@@ -168,7 +165,6 @@ class AssetsController extends Controller
// Create the image (if one was chosen.)
if (Input::has('image')) {
$image = Input::get('image');
// After modification, the image is prefixed by mime info like the following:
@@ -201,7 +197,6 @@ class AssetsController extends Controller
->put('default', $messageBag));
return response()->json(['image' => $e->getMessage()], 422);
}
}
@@ -211,31 +206,26 @@ class AssetsController extends Controller
// Need to investigate and fix. Using static method for now.
$model = AssetModel::find($request->get('model_id'));
if ($model->fieldset) {
foreach ($model->fieldset->fields as $field) {
if ($field->field_encrypted=='1') {
if (Gate::allows('admin')) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
}
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
}
}
// Was the asset created?
if ($asset->save()) {
$asset->logCreate();
if(request('assigned_user')) {
if (request('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif(request('assigned_asset')) {
} elseif (request('assigned_asset')) {
$target = Asset::find(request('assigned_asset'));
} elseif(request('assigned_location')) {
} elseif (request('assigned_location')) {
$target = Location::find(request('assigned_location'));
}
if (isset($target)) {
@@ -268,15 +258,15 @@ class AssetsController extends Controller
$this->authorize($item);
return view('hardware/edit', compact('item'))
->with('model_list', Helper::modelList())
->with('supplier_list', Helper::suppliersList())
->with('company_list', Helper::companyList())
->with('locations_list', Helper::locationsList())
->with('statuslabel_list', Helper::statusLabelList())
->with('assigned_to', Helper::usersList())
->with('manufacturer', Helper::manufacturerList())
->with('statuslabel_types', Helper::statusTypeList())
->with('category', Helper::categoryList('asset'));
->with('model_list', Helper::modelList())
->with('supplier_list', Helper::suppliersList())
->with('company_list', Helper::companyList())
->with('locations_list', Helper::locationsList())
->with('statuslabel_list', Helper::statusLabelList())
->with('assigned_to', Helper::usersList())
->with('manufacturer', Helper::manufacturerList())
->with('statuslabel_types', Helper::statusTypeList())
->with('category', Helper::categoryList('asset'));
}
@@ -291,7 +281,6 @@ class AssetsController extends Controller
public function update(AssetRequest $request, $assetId = null)
{
// Check if the asset exists
if (!$asset = Asset::find($assetId)) {
// Redirect to the asset management page with error
@@ -369,7 +358,6 @@ class AssetsController extends Controller
if (Gate::allows('admin')) {
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
}
} else {
$asset->{$field->convertUnicodeDbSlug()} = $request->input($field->convertUnicodeDbSlug());
}
@@ -385,7 +373,6 @@ class AssetsController extends Controller
\Input::flash();
\Session::flash('errors', $asset->getErrors());
return response()->json(['errors' => $asset->getErrors()], 500);
}
/**
@@ -407,11 +394,18 @@ class AssetsController extends Controller
$this->authorize('delete', $asset);
DB::table('assets')
->where('id', $asset->id)
->update(array('assigned_to' => null));
->where('id', $asset->id)
->update(array('assigned_to' => null));
$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;
$log = $logaction->logaction('deleted');
// Redirect to the asset management page
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
}
@@ -438,9 +432,8 @@ class AssetsController extends Controller
// Get the dropdown of users and then pass it to the checkout view
return view('hardware/checkout', compact('asset'))
->with('users_list', Helper::usersList())
->with('assets_list', Helper::assetsList())
->with('assets_list', Helper::detailedAssetList())
->with('locations_list', Helper::locationsList());
}
/**
@@ -462,11 +455,11 @@ class AssetsController extends Controller
}
$this->authorize('checkout', $asset);
if(request('assigned_user')) {
if (request('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif(request('assigned_asset')) {
} elseif (request('assigned_asset')) {
$target = Asset::find(request('assigned_asset'));
} elseif(request('assigned_location')) {
} elseif (request('assigned_location')) {
$target = Location::find(request('assigned_location'));
}
// $user = User::find(Input::get('assigned_to'));
@@ -512,7 +505,6 @@ class AssetsController extends Controller
$this->authorize('checkin', $asset);
return view('hardware/checkin', compact('asset'))->with('statusLabel_list', Helper::statusLabelList())->with('backto', $backto);
}
@@ -537,17 +529,18 @@ class AssetsController extends Controller
$this->authorize('checkin', $asset);
$admin = Auth::user();
$user = $asset->assignedUser;
if ($asset->assignedType() == Asset::USER) {
$user = $asset->assignedTo;
}
if (is_null($target = $asset->assignedTo)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
}
// This is just used for the redirect
$return_to = $asset->assigned_to;
$asset->expected_checkin = null;
$asset->last_checkout = null;
$asset->assigned_to = null;
$asset->assignedTo()->disassociate($asset);
$asset->assigned_type = null;
$asset->accepted = null;
$asset->name = e(Input::get('name'));
@@ -565,8 +558,11 @@ class AssetsController extends Controller
$data['item_tag'] = $asset->asset_tag;
$data['item_serial'] = $asset->serial;
$data['note'] = $logaction->note;
$data['manufacturer_name'] = $asset->model->manufacturer->name;
$data['model_name'] = $asset->model->name;
$data['model_number'] = $asset->model->model_number;
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!config('app.lock_passwords'))) {
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!empty($user->email)) && (!config('app.lock_passwords'))) {
Mail::send('emails.checkin-asset', $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'));
@@ -575,7 +571,7 @@ class AssetsController extends Controller
}
if ($backto=='user') {
return redirect()->to("admin/users/".$return_to.'/view')->with('success', trans('admin/hardware/message.checkin.success'));
return redirect()->route("users.show", $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
}
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
}
@@ -599,15 +595,16 @@ class AssetsController extends Controller
$asset = Asset::withTrashed()->find($assetId);
$this->authorize('view', $asset);
$settings = Setting::getSettings();
$audit_log = Actionlog::where('action_type','=','audit')->where('item_id','=',$assetId)->where('item_type','=',Asset::class)->orderBy('created_at','DESC')->first();
$audit_log = Actionlog::where('action_type', '=', 'audit')
->where('item_id', '=', $assetId)
->where('item_type', '=', Asset::class)
->orderBy('created_at', 'DESC')->first();
if (isset($asset)) {
if (!is_null($asset->assetloc)) {
$use_currency = $asset->assetloc->currency;
} else {
if ($settings->default_currency!='') {
$use_currency = $settings->default_currency;
} else {
@@ -621,7 +618,7 @@ class AssetsController extends Controller
);
return view('hardware/view', compact('asset', 'qr_code', 'settings'))
->with('use_currency', $use_currency)->with('audit_log',$audit_log);
->with('use_currency', $use_currency)->with('audit_log', $audit_log);
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist', compact('id')));
@@ -640,12 +637,11 @@ class AssetsController extends Controller
$settings = Setting::getSettings();
if ($settings->qr_code == '1') {
$asset = Asset::find($assetId);
$asset = Asset::withTrashed()->find($assetId);
$size = Helper::barcodeDimensions($settings->barcode_type);
$qr_file = public_path().'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'.png';
if (isset($asset->id,$asset->asset_tag)) {
$qr_file = public_path().'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png';
if (isset($asset->id, $asset->asset_tag)) {
if (file_exists($qr_file)) {
$header = ['Content-type' => 'image/png'];
return response()->file($qr_file, $header);
@@ -657,7 +653,6 @@ class AssetsController extends Controller
}
}
}
}
@@ -675,19 +670,18 @@ class AssetsController extends Controller
$asset = Asset::find($assetId);
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
if (isset($asset->id,$asset->asset_tag)) {
if (isset($asset->id, $asset->asset_tag)) {
if (file_exists($barcode_file)) {
$header = ['Content-type' => 'image/png'];
return response()->file($barcode_file, $header);
} else {
$barcode = new \Com\Tecnick\Barcode\Barcode();
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode, $asset->asset_tag, 250, 20);
$barcode_obj = $barcode->getBarcodeObj($settings->alt_barcode,$asset->asset_tag,300,50);
file_put_contents($barcode_file, $barcode_obj->getPngData());
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
}
}
}
/**
@@ -754,7 +748,6 @@ class AssetsController extends Controller
*/
public function postImportHistory(Request $request)
{
if (!ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
@@ -772,9 +765,7 @@ class AssetsController extends Controller
foreach ($results as $row) {
if (is_array($row)) {
$row = array_change_key_case($row, CASE_LOWER);
$asset_tag = Helper::array_smart_fetch($row, "asset tag");
if (!array_key_exists($asset_tag, $item)) {
@@ -789,7 +780,6 @@ class AssetsController extends Controller
$item[$asset_tag][$batch_counter]['email'] = Helper::array_smart_fetch($row, "email");
if ($asset = Asset::where('asset_tag', '=', $asset_tag)->first()) {
$item[$asset_tag][$batch_counter]['asset_id'] = $asset->id;
$base_username = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $item[$asset_tag][$batch_counter]['name']);
@@ -846,12 +836,10 @@ class AssetsController extends Controller
} else {
$status['error'][]['asset'][$asset_tag]['msg'] = 'Asset and user was matched but could not be saved.';
}
} else {
$item[$asset_tag][$batch_counter]['checkedout_to'] = null;
$status['error'][]['user'][Helper::array_smart_fetch($row, "name")]['msg'] = 'User does not exist so no checkin log was created.';
}
} else {
$item[$asset_tag][$batch_counter]['asset_id'] = null;
$status['error'][]['asset'][$asset_tag]['msg'] = 'Asset does not exist so no match was attempted.';
@@ -867,7 +855,6 @@ class AssetsController extends Controller
// Only do this if a matching user was found
if ((array_key_exists('checkedout_to', $asset_batch[$x])) && ($asset_batch[$x]['checkedout_to']!='')) {
if (($total_in_batch > 1) && ($x < $total_in_batch) && (array_key_exists($next, $asset_batch))) {
$checkin_date = Carbon::parse($asset_batch[$next]['checkout_date'])->subDay(1)->format('Y-m-d H:i:s');
$asset_batch[$x]['real_checkin'] = $checkin_date;
@@ -957,7 +944,7 @@ class AssetsController extends Controller
* @since [v1.0]
* @return View
*/
public function getDeleteFile($assetId = null, $fileId = null)
public function deleteFile($assetId = null, $fileId = null)
{
$asset = Asset::find($assetId);
$this->authorize('update', $asset);
@@ -974,7 +961,6 @@ class AssetsController extends Controller
}
$log->delete();
return redirect()->back()->with('success', trans('admin/hardware/message.deletefile.success'));
}
// Prepare the error message
$error = trans('admin/hardware/message.does_not_exist', compact('id'));
@@ -1041,25 +1027,19 @@ class AssetsController extends Controller
if ($request->has('bulk_actions')) {
if ($request->input('bulk_actions')=='labels') {
$count = 0;
return view('hardware/labels')
->with('assets', Asset::find($asset_ids))
->with('settings', Setting::getSettings())
->with('count', $count)
->with('settings',
Setting::getSettings()
);
->with('settings', Setting::getSettings());
} elseif ($request->input('bulk_actions')=='delete') {
$assets = Asset::with('assignedTo', 'assetloc')->find($asset_ids);
$assets->each(function($asset) {
$this->authorize('delete',$asset);
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
return view('hardware/bulk-delete')->with('assets', $assets);
// Bulk edit
} elseif ($request->input('bulk_actions')=='edit') {
return view('hardware/bulk')
@@ -1140,9 +1120,8 @@ class AssetsController extends Controller
}
DB::table('assets')
->where('id', $key)
->update($update_array);
->where('id', $key)
->update($update_array);
} // endforeach
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.update.success'));
// no values given, nothing to update
@@ -1163,8 +1142,7 @@ class AssetsController extends Controller
public function postBulkDelete()
{
$this->authorize('delete', Asset::class);
if (Input::has('ids')) {
$assets = Asset::find(Input::get('ids'));
foreach ($assets as $asset) {
@@ -1172,9 +1150,8 @@ class AssetsController extends Controller
$update_array['assigned_to'] = null;
DB::table('assets')
->where('id', $asset->id)
->update($update_array);
->where('id', $asset->id)
->update($update_array);
} // endforeach
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.delete.success'));
// no values given, nothing to update
@@ -1222,7 +1199,7 @@ class AssetsController extends Controller
foreach ($asset_ids as $asset_id) {
$asset = Asset::find($asset_id);
$this->authorize('checkout', $asset);
$error = $asset->checkOutToUser($user, $admin, $checkout_at, $expected_checkin, e(Input::get('note')), null);
$error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, e(Input::get('note')), null);
if ($error) {
array_merge_recursive($errors, $asset->getErrors()->toArray());
@@ -1238,28 +1215,44 @@ class AssetsController extends Controller
return redirect()->to("hardware/bulk-checkout")->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
}
public function quickScan(Request $request)
{
$this->authorize('audit', Asset::class);
$dt = Carbon::now()->addMonths(12)->toDateString();
return view('hardware/quickscan')->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
}
public function audit(Request $request, $id)
{
$this->authorize('audit', Asset::class);
$dt = Carbon::now()->addMonths(12)->toDateString();
$asset = Asset::findOrFail($id);
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt);
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
}
public function auditStore(Request $request, $id)
{
$this->authorize('audit', Asset::class);
$rules = array(
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable'
);
$validator = \Validator::make($request->all(), $rules);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
}
$asset = Asset::findOrFail($id);
$asset->next_audit_date = $request->input('next_audit_date');
if ($asset->save()) {
$asset->logAudit(request('note'));
$asset->logAudit(request('note'), request('location_id'));
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success'));
}
}
}
@@ -47,6 +47,7 @@ class LoginController extends Controller
public function __construct()
{
$this->middleware('guest', ['except' => ['logout','postTwoFactorAuth','getTwoFactorAuth','getTwoFactorEnroll']]);
\Session::put('backUrl', \URL::previous());
}
@@ -320,4 +321,9 @@ class LoginController extends Controller
return redirect()->route('login');
}
public function redirectTo()
{
return Session::get('backUrl') ? Session::get('backUrl') : $this->redirectTo;
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class RegisterController extends Controller
{
public function __construct()
{
$this->middleware('guest');
}
}
@@ -25,7 +25,7 @@ class ResetPasswordController extends Controller
*
* @var string
*/
protected $redirectTo = '/home';
protected $redirectTo = '/';
/**
* Create a new controller instance.
@@ -98,10 +98,8 @@ class CategoriesController extends Controller
*/
public function edit($categoryId = null)
{
// Check if the category exists
if (is_null($item = Category::find($categoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.does_not_exist'));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.does_not_exist'));
}
$category_types= Helper::categoryTypeList();
@@ -158,22 +156,22 @@ class CategoriesController extends Controller
{
// Check if the category exists
if (is_null($category = Category::find($categoryId))) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.not_found'));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found'));
}
if ($category->has_models() > 0) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'model']));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'model']));
} elseif ($category->accessories()->count() > 0) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory']));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory']));
} elseif ($category->consumables()->count() > 0) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable']));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable']));
} elseif ($category->components()->count() > 0) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component']));
return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component']));
}
$category->delete();
// Redirect to the locations management page
return redirect()->to(route('categories.index'))->with('success', trans('admin/categories/message.delete.success'));
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success'));
}
+12 -43
View File
@@ -74,20 +74,20 @@ class ComponentsController extends Controller
* @since [v3.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function store()
public function store(Request $request)
{
$this->authorize('create', Component::class);
$component = new Component();
$component->name = Input::get('name');
$component->category_id = Input::get('category_id');
$component->location_id = Input::get('location_id');
$component->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$component->order_number = Input::get('order_number');
$component->min_amt = Input::get('min_amt');
$component->serial = Input::get('serial');
$component->purchase_date = Input::get('purchase_date');
$component->purchase_cost = request('purchase_cost');
$component->qty = Input::get('qty');
$component->name = $request->input('name');
$component->category_id = $request->input('category_id');
$component->location_id = $request->input('location_id');
$component->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$component->order_number = $request->input('order_number', null);
$component->min_amt = $request->input('min_amt', null);
$component->serial = $request->input('serial', null);
$component->purchase_date = $request->input('purchase_date', null);
$component->purchase_cost = $request->input('purchase_cost', null);
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
if ($component->save()) {
@@ -283,40 +283,9 @@ class ComponentsController extends Controller
'asset_id' => $asset_id
]);
$component->logCheckout(e(Input::get('note')), $asset_id);
$component->logCheckout(e(Input::get('note')), $asset);
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
}
/**
* Return JSON data to populate the components view,
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getView() method that returns the view.
* @since [v3.0]
* @param int $componentId
* @return string JSON
*/
public function getDataView($componentId)
{
if (is_null($component = Component::with('assets')->find($componentId))) {
// Redirect to the component management page with error
return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found'));
}
if (!Company::isCurrentUserHasAccess($component)) {
return ['total' => 0, 'rows' => []];
}
$this->authorize('view', $component);
$rows = array();
$all_custom_fields = CustomField::all(); // Cached for table;
foreach ($component->assets as $component_assignment) {
$rows[] = $component_assignment->present()->forDataTable($all_custom_fields);
}
$componentCount = $component->assets->count();
$data = array('total' => $componentCount, 'rows' => $rows);
return $data;
}
}
+1 -44
View File
@@ -250,7 +250,7 @@ class ConsumablesController extends Controller
'assigned_to' => e(Input::get('assigned_to'))
]);
$logaction = $consumable->logCheckout(e(Input::get('note')));
$logaction = $consumable->logCheckout(e(Input::get('note')), $user);
$data['log_id'] = $logaction->id;
$data['eula'] = $consumable->getEula();
$data['first_name'] = $user->first_name;
@@ -273,47 +273,4 @@ class ConsumablesController extends Controller
}
/**
* Returns a JSON response containing details on the users associated with this consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getView() method that returns the form.
* @since [v1.0]
* @param int $consumableId
* @return array
*/
public function getDataView($consumableId)
{
//$consumable = Consumable::find($consumableID);
$consumable = Consumable::with(array('consumableAssigments'=>
function ($query) {
$query->orderBy('created_at', 'DESC');
},
'consumableAssigments.admin'=> function ($query) {
},
'consumableAssigments.user'=> function ($query) {
},
))->find($consumableId);
// $consumable->load('consumableAssigments.admin','consumableAssigments.user');
if (!Company::isCurrentUserHasAccess($consumable)) {
return ['total' => 0, 'rows' => []];
}
$this->authorize('view', Component::class);
$rows = array();
foreach ($consumable->consumableAssigments as $consumable_assignment) {
$rows[] = [
'name' => $consumable_assignment->user->present()->nameUrl(),
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
];
}
$consumableCount = $consumable->users->count();
$data = array('total' => $consumableCount, 'rows' => $rows);
return $data;
}
}
@@ -37,19 +37,25 @@ class CustomFieldsetsController extends Controller
public function show($id)
{
$cfset = CustomFieldset::with('fields')->where('id', '=', $id)->orderBy('id', 'ASC')->first();
$custom_fields_list = ["" => "Add New Field to Fieldset"] + CustomField::pluck("name", "id")->toArray();
$maxid = 0;
foreach ($cfset->fields() as $field) {
if ($field->pivot->order > $maxid) {
$maxid=$field->pivot->order;
}
if (isset($custom_fields_list[$field->id])) {
unset($custom_fields_list[$field->id]);
if ($cfset) {
$custom_fields_list = ["" => "Add New Field to Fieldset"] + CustomField::pluck("name", "id")->toArray();
$maxid = 0;
foreach ($cfset->fields() as $field) {
if ($field->pivot->order > $maxid) {
$maxid=$field->pivot->order;
}
if (isset($custom_fields_list[$field->id])) {
unset($custom_fields_list[$field->id]);
}
}
return view("custom_fields.fieldsets.view")->with("custom_fieldset", $cfset)->with("maxid", $maxid+1)->with("custom_fields_list", $custom_fields_list);
}
return view("custom_fields.fieldsets.view")->with("custom_fieldset", $cfset)->with("maxid", $maxid+1)->with("custom_fields_list", $custom_fields_list);
return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.does_not_exist'));
}
@@ -133,16 +139,21 @@ class CustomFieldsetsController extends Controller
*/
public function destroy($id)
{
//
$fieldset = CustomFieldset::find($id);
$models = AssetModel::where("fieldset_id", "=", $id);
if ($models->count() == 0) {
$fieldset->delete();
return redirect()->route("fields.show")->with("success", trans('admin/custom_fields/message.fieldset.delete.success'));
} else {
return redirect()->route("fields.show")->with("error", trans('admin/custom_fields/message.fieldset.delete.in_use'));
if ($fieldset) {
$models = AssetModel::where("fieldset_id", "=", $id);
if ($models->count() == 0) {
$fieldset->delete();
return redirect()->route("fields.index")->with("success", trans('admin/custom_fields/message.fieldset.delete.success'));
} else {
return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.delete.in_use'));
}
}
return redirect()->route("fields.index")->with("error", trans('admin/custom_fields/message.fieldset.does_not_exist'));
}
+1 -1
View File
@@ -39,8 +39,8 @@ class DashboardController extends Controller
$counts['grand_total'] = $counts['asset'] + $counts['accessory'] + $counts['license'] + $counts['consumable'];
if ((!file_exists(storage_path().'/oauth-private.key')) || (!file_exists(storage_path().'/oauth-public.key'))) {
\Artisan::call('passport:install');
\Artisan::call('migrate', ['--force' => true]);
\Artisan::call('passport:install');
}
return view('dashboard')->with('asset_stats', $asset_stats)->with('counts', $counts);
+4 -13
View File
@@ -27,13 +27,11 @@ class DepartmentsController extends Controller
public function index(Request $request)
{
$this->authorize('index', Department::class);
$company = null;
if ($request->has('company_id')) {
$company = Company::find($request->input('company_id'));
} else {
$company = null;
}
return view('departments/index')->with('company',$company);
return view('departments/index')->with('company', $company);
}
@@ -53,12 +51,10 @@ class DepartmentsController extends Controller
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
if ($department->save()) {
return redirect()->route("departments.index")->with('success', trans('admin/departments/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($department->getErrors());
}
/**
@@ -140,25 +136,20 @@ class DepartmentsController extends Controller
->with('location_list', Helper::locationsList())
->with('company_list', Helper::companyList());
}
public function update(Request $request, $id) {
$this->authorize('create', Department::class);
if (is_null($department = Department::find($id))) {
return redirect()->to('admin/settings/departments')->with('error', trans('admin/departments/message.does_not_exist'));
return redirect()->route('departments.index')->with('error', trans('admin/departments/message.does_not_exist'));
}
$department->fill($request->all());
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
if ($department->save()) {
return redirect()->route("departments.index")->with('success', trans('admin/departments/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($department->getErrors());
}
}
@@ -155,5 +155,24 @@ class DepreciationsController extends Controller
return redirect()->route('depreciations.index')->with('success', trans('admin/depreciations/message.delete.success'));
}
/**
* Returns a view that displays a form to display depreciation listing
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postEdit()
* @param int $depreciationId
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
*/
public function show($id)
{
if (is_null($depreciation = Depreciation::find($id))) {
// Redirect to the blogs management page
return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
return view('depreciations/view', compact('depreciation'));
}
}
+29 -4
View File
@@ -87,10 +87,15 @@ class GroupsController extends Controller
public function edit($id = null)
{
$group = Group::find($id);
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
if ($group) {
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
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')));
}
/**
@@ -142,4 +147,24 @@ class GroupsController extends Controller
return redirect()->route('groups.index')->with('error', trans('general.feature_disabled'));
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the group detail page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v4.0.11]
* @return \Illuminate\Contracts\View\View
*/
public function show($id)
{
$group = Group::find($id);
if ($group) {
return view('groups/view', compact('group'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
}
+25 -71
View File
@@ -279,7 +279,7 @@ class LicensesController extends Controller
// Declare the rules for the form validation
$rules = [
'note' => 'string',
'note' => 'string|nullable',
'asset_id' => 'required_without:assigned_to',
];
@@ -291,23 +291,23 @@ class LicensesController extends Controller
// Ooops.. something went wrong
return redirect()->back()->withInput()->withErrors($validator);
}
$target = null;
if ($assigned_to!='') {
// Check if the user exists
if (is_null($is_assigned_to = User::find($assigned_to))) {
if (is_null($target = User::find($assigned_to))) {
// Redirect to the asset management page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist'));
}
}
if ($asset_id!='') {
if (is_null($asset = Asset::find($asset_id))) {
if (is_null($target = Asset::find($asset_id))) {
// Redirect to the asset management page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
}
if (($asset->assigned_to!='') && (($asset->assigned_to!=$assigned_to)) && ($assigned_to!='')) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.owner_doesnt_match_asset'));
if (($request->has('assigned_to')) && ($request->has('asset_id'))) {
return redirect()->back()->withInput()->with('error', trans('admin/licenses/message.select_asset_or_person'));
}
}
@@ -332,17 +332,16 @@ class LicensesController extends Controller
// Was the asset updated?
if ($licenseSeat->save()) {
$licenseSeat->logCheckout($request->input('note'));
$licenseSeat->logCheckout($request->input('note'), $target);
$data['license_id'] =$licenseSeat->license_id;
$data['license_id'] = $licenseSeat->license_id;
$data['note'] = $request->input('note');
// Redirect to the new asset page
return redirect()->route("licenses.index")->with('success', trans('admin/licenses/message.checkout.success'));
}
// Redirect to the asset management page with error
return redirect()->to("admin/licenses/{$asset_id}/checkout")->with('error', trans('admin/licenses/message.create.error'))->with('license', new License);
return redirect()->route("licenses.index")->with('error', trans('admin/licenses/message.checkout.error'));
}
@@ -358,12 +357,12 @@ class LicensesController extends Controller
public function getCheckin($seatId = null, $backTo = null)
{
// Check if the asset exists
if (is_null($licenseseat = LicenseSeat::find($seatId))) {
if (is_null($licenseSeat = LicenseSeat::find($seatId))) {
// 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);
return view('licenses/checkin', compact('licenseseat'))->with('backto', $backTo);
$this->authorize('checkin', $licenseSeat);
return view('licenses/checkin', compact('licenseSeat'))->with('backto', $backTo);
}
@@ -440,7 +439,10 @@ class LicensesController extends Controller
*/
public function show($licenseId = null)
{
$license = License::find($licenseId);
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
if (isset($license->id)) {
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
$this->authorize('view', $license);
@@ -488,7 +490,7 @@ class LicensesController extends Controller
* @param int $licenseId
* @return \Illuminate\Http\RedirectResponse
*/
public function postUpload($licenseId = null)
public function postUpload(Request $request, $licenseId = null)
{
$license = License::find($licenseId);
// the license is valid
@@ -517,13 +519,16 @@ class LicensesController extends Controller
//Log the upload to the log
$license->logUpload($filename, e($request->input('notes')));
}
// This being called from a modal seems to confuse redirect()->back()
// It thinks we should go to the dashboard. As this is only used
// from the modal at present, hardcode the redirect. Longterm
// maybe we evaluate something else.
if ($upload_success) {
return redirect()->back()->with('success', trans('admin/licenses/message.upload.success'));
return redirect()->route('licenses.show', $license->id)->with('success', trans('admin/licenses/message.upload.success'));
}
return redirect()->back()->with('error', trans('admin/licenses/message.upload.error'));
return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.error'));
}
return redirect()->back()->with('error', trans('admin/licenses/message.upload.nofiles'));
return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.nofiles'));
}
// Prepare the error message
$error = trans('admin/licenses/message.does_not_exist', compact('id'));
@@ -586,61 +591,10 @@ class LicensesController extends Controller
$file = $log->get_src('licenses');
return Response::download($file);
}
// Prepare the error message
$error = trans('admin/licenses/message.does_not_exist', compact('id'));
// Redirect to the licence management page
return redirect()->route('licenses.index')->with('error', $error);
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', compact('id')));
}
/**
* Generates a JSON response to populate the licence index datatables.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LicensesController::getIndex() method that provides the view
* @since [v1.0]
* @return String JSON
*/
public function getDatatable(Request $request)
{
$this->authorize('view', License::class);
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer'));
if (Input::has('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['id','name','purchase_cost','expiration_date','purchase_order','order_number','notes','purchase_date','serial','manufacturer','company'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
switch ($sort) {
case 'manufacturer':
$licenses = $licenses->OrderManufacturer($order);
break;
case 'company':
$licenses = $licenses->OrderCompany($order);
break;
default:
$licenses = $licenses->orderBy($sort, $order);
break;
}
$licenseCount = $licenses->count();
$licenses = $licenses->skip($offset)->take($limit)->get();
$rows = array();
foreach ($licenses as $license) {
$rows[] = $license->present()->forDataTable();
}
$data = array('total' => $licenseCount, 'rows' => $rows);
return $data;
}
/**
* Generates the next free seat ID for checkout.
+3 -4
View File
@@ -89,6 +89,7 @@ class LocationsController extends Controller
$location->state = Input::get('state');
$location->country = Input::get('country');
$location->zip = Input::get('zip');
$location->ldap_ou = Input::get('ldap_ou');
$location->manager_id = Input::get('manager_id');
$location->user_id = Auth::id();
@@ -147,7 +148,7 @@ class LocationsController extends Controller
{
// Check if the location exists
if (is_null($item = Location::find($locationId))) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.does_not_exist'));
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
// Show the page
@@ -156,7 +157,6 @@ class LocationsController extends Controller
$location_options = Location::flattenLocationsArray($location_options_array);
$location_options = array('' => 'Top Level') + $location_options;
return view('locations/edit', compact('item'))
->with('location_options', $location_options)
->with('manager_list', Helper::managerList());
@@ -176,7 +176,7 @@ class LocationsController extends Controller
{
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.does_not_exist'));
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
// Update the location data
@@ -217,7 +217,6 @@ class LocationsController extends Controller
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.not_found'));
}
if ($location->users->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users'));
} elseif ($location->childLocations->count() > 0) {
@@ -212,116 +212,5 @@ class ManufacturersController extends Controller
}
protected function getDataAssetsView(Manufacturer $manufacturer, Request $request)
{
$manufacturer = $manufacturer->load('assets.model', 'assets.assignedTo', 'assets.assetstatus', 'assets.company');
$manufacturer_assets = $manufacturer->assets();
if ($request->has('search')) {
$manufacturer_assets = $manufacturer_assets->TextSearch(e($request->input('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$count = $manufacturer_assets->count();
$manufacturer_assets = $manufacturer_assets->skip($offset)->take($limit)->get();
$rows = array();
$all_custom_fields = CustomField::all(); // cached;
foreach ($manufacturer_assets as $asset) {
$rows[] = $asset->present()->forDataTable($all_custom_fields);
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
protected function getDataLicensesView(Manufacturer $manufacturer, Request $request)
{
$manufacturer = $manufacturer->load('licenses.company', 'licenses.manufacturer', 'licenses.licenseSeatsRelation');
$licenses = $manufacturer->licenses;
if ($request->has('search')) {
$licenses = $licenses->TextSearch($request->input('search'));
}
$licenseCount = $licenses->count();
$rows = array();
foreach ($licenses as $license) {
$rows[] = $license->present()->forDataTable();
}
$data = array('total' => $licenseCount, 'rows' => $rows);
return $data;
}
public function getDataAccessoriesView(Manufacturer $manufacturer, Request $request)
{
$manufacturer = $manufacturer->load(
'accessories.location',
'accessories.company',
'accessories.category',
'accessories.manufacturer',
'accessories.users'
);
$accessories = $manufacturer->accessories();
if ($request->has('search')) {
$accessories = $accessories->TextSearch(e($request->input('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$accessCount = $accessories->count();
$accessories = $accessories->skip($offset)->take($limit)->get();
$rows = array();
foreach ($accessories as $accessory) {
$rows[] = $accessory->present()->forDataTable();
}
$data = array('total'=>$accessCount, 'rows'=>$rows);
return $data;
}
public function getDataConsumablesView($manufacturer, Request $request)
{
$manufacturer = $manufacturer->load(
'consumables.location',
'consumables.company',
'consumables.category',
'consumables.manufacturer',
'consumables.users'
);
$consumables = $manufacturer->consumables();
if ($request->has('search')) {
$consumables = $consumables->TextSearch(e($request->input('search')));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
$consumCount = $consumables->count();
$consumables = $consumables->skip($offset)->take($limit)->get();
$rows = array();
foreach ($consumables as $consumable) {
$rows[] = $consumable->present()->forDataTable();
}
$data = array('total' => $consumCount, 'rows' => $rows);
return $data;
}
}
+46 -17
View File
@@ -15,6 +15,7 @@ use Illuminate\Support\Facades\View;
use Input;
use League\Csv\Reader;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Http\Request;
/**
* This controller handles all actions related to Reports for
@@ -102,18 +103,45 @@ class ReportsController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function exportAssetReport()
public function exportAssetReport(Request $request)
{
\Debugbar::disable();
$customfields = CustomField::get();
$response = new StreamedResponse(function () use ($customfields) {
$response = new StreamedResponse(function () use ($customfields, $request) {
// Open output stream
$handle = fopen('php://output', 'w');
Asset::with('assignedTo', 'assetLoc','defaultLoc','assignedTo','model','supplier','assetstatus','model.manufacturer')->orderBy('created_at', 'DESC')->chunk(500, function($assets) use($handle, $customfields) {
$assets = Asset::with('assignedTo', 'assetLoc','defaultLoc','assignedTo','model','supplier','assetstatus','model.manufacturer');
// This is used by the sidenav, mostly
switch ($request->input('status')) {
case 'Deleted':
$assets->withTrashed()->Deleted();
break;
case 'Pending':
$assets->Pending();
break;
case 'RTD':
$assets->RTD();
break;
case 'Undeployable':
$assets->Undeployable();
break;
case 'Archived':
$assets->Archived();
break;
case 'Requestable':
$assets->RequestableAssets();
break;
case 'Deployed':
$assets->Deployed();
break;
}
$assets->orderBy('created_at', 'DESC')->chunk(500, function($assets) use($handle, $customfields) {
$headers=[
trans('general.company'),
trans('admin/hardware/table.asset_tag'),
@@ -126,7 +154,7 @@ class ReportsController extends Controller
trans('admin/hardware/table.purchase_date'),
trans('admin/hardware/table.purchase_cost'),
trans('admin/hardware/form.order'),
trans('admin/hardware/form.supplier'),
trans('general.supplier'),
trans('admin/hardware/table.checkoutto'),
trans('admin/hardware/table.checkout_date'),
trans('admin/hardware/table.location'),
@@ -154,7 +182,7 @@ class ReportsController extends Controller
($asset->supplier) ? e($asset->supplier->name) : '',
($asset->assignedTo) ? e($asset->assignedTo->present()->name()) : '',
($asset->last_checkout!='') ? e($asset->last_checkout) : '',
e($asset->assetLoc->present()->name()),
($asset->assetLoc) ? e($asset->assetLoc->present()->name()) : '',
($asset->notes) ? e($asset->notes) : '',
];
foreach ($customfields as $field) {
@@ -168,7 +196,8 @@ class ReportsController extends Controller
fclose($handle);
}, 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="assets-'.date('Y-m-d-his').'.csv"',
'Content-Disposition'
=> 'attachment; filename="'.(($request->has('status')) ? trim($request->input('status')) : 'all').'-assets-'.date('Y-m-d-his').'.csv"',
]);
return $response;
@@ -186,7 +215,7 @@ class ReportsController extends Controller
{
// Grab all the assets
$assets = Asset::with('model', 'assignedTo', 'assetstatus', 'defaultLoc', 'assetlog', 'company')
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'assetloc', 'assetlog', 'company', 'model.category', 'model.depreciation')
->orderBy('created_at', 'DESC')->get();
return view('reports/depreciation', compact('assets'));
@@ -390,7 +419,7 @@ class ReportsController extends Controller
*/
public function postCustom()
{
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assigneduser', 'assetloc', 'defaultLoc', 'assigneduser.userloc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assignedTo', 'assetloc', 'defaultLoc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
$customfields = CustomField::get();
$rows = [ ];
@@ -463,7 +492,7 @@ class ReportsController extends Controller
}
if (e(Input::get('notes')) == '1') {
$header[] = 'Notes';
$header[] = trans('general.notes');
}
@@ -543,8 +572,8 @@ class ReportsController extends Controller
if (e(Input::get('assigned_to')) == '1') {
if ($asset->assignedTo) {
$row[] = '"' .e($asset->assignedTo->present()->name()). '"';
if ($asset->assignedto) {
$row[] = '"' .e($asset->assignedto->present()->name()). '"';
} else {
$row[] = ''; // Empty string if unassigned
}
@@ -552,8 +581,8 @@ class ReportsController extends Controller
if (e(Input::get('username')) == '1') {
// Only works if we're checked out to a user, not anything else.
if ($asset->assigneduser) {
$row[] = '"' .e($asset->assigneduser->username). '"';
if ($asset->checkedOutToUser()) {
$row[] = '"' .e($asset->assignedto->username). '"';
} else {
$row[] = ''; // Empty string if unassigned
}
@@ -561,8 +590,8 @@ class ReportsController extends Controller
if (e(Input::get('employee_num')) == '1') {
// Only works if we're checked out to a user, not anything else.
if ($asset->assigneduser) {
$row[] = '"' .e($asset->assigneduser->employee_num). '"';
if ($asset->checkedOutToUser()) {
$row[] = '"' .e($asset->assignedto->employee_num). '"';
} else {
$row[] = ''; // Empty string if unassigned
}
@@ -604,9 +633,9 @@ class ReportsController extends Controller
if (e(Input::get('notes')) == '1') {
if ($asset->notes) {
$row[] = '"' .$asset->notes. '"';
$row[] = '"' .$asset->notes . '"';
} else {
$row[] = ''; // Empty string if unassigned
$row[] = '';
}
}
+13 -4
View File
@@ -20,6 +20,7 @@ use Auth;
use App\Models\User;
use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsLdapRequest;
/**
* This controller handles all actions related to Settings for
@@ -262,8 +263,8 @@ class SettingsController extends Controller
$output = Artisan::output();
if ((!file_exists(storage_path().'/oauth-private.key')) || (!file_exists(storage_path().'/oauth-public.key'))) {
Artisan::call('passport:install');
Artisan::call('migrate', ['--force' => true]);
Artisan::call('passport:install');
}
@@ -337,7 +338,10 @@ class SettingsController extends Controller
$setting->email_format = $request->input('email_format');
$setting->username_format = $request->input('username_format');
$setting->require_accept_signature = $request->input('require_accept_signature');
$setting->login_note = $request->input('login_note');
if (!config('app.lock_passwords')) {
$setting->login_note = $request->input('login_note');
}
$setting->default_eula_text = $request->input('default_eula_text');
$setting->thumbnail_max_h = $request->input('thumbnail_max_h');
@@ -387,6 +391,7 @@ class SettingsController extends Controller
$setting->brand = $request->input('brand', '1');
$setting->header_color = $request->input('header_color');
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0');
// Only allow the site name and CSS to be changed if lock_passwords is false
@@ -410,7 +415,7 @@ class SettingsController extends Controller
$file_name = "logo.".$image->getClientOriginalExtension();
$path = public_path('uploads');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 40, function ($constraint) {
Image::make($image->getRealPath())->resize(null, 150, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
@@ -562,10 +567,12 @@ class SettingsController extends Controller
$alert_email = rtrim($request->input('alert_email'), ',');
$alert_email = trim($alert_email);
$setting->alert_email = e($alert_email);
$setting->alert_email = $alert_email;
$setting->alerts_enabled = $request->input('alerts_enabled', '0');
$setting->alert_interval = $request->input('alert_interval');
$setting->alert_threshold = $request->input('alert_threshold');
$setting->audit_interval = $request->input('audit_interval');
$setting->audit_warning_days = $request->input('audit_warning_days');
if ($setting->save()) {
return redirect()->route('settings.index')
@@ -989,6 +996,8 @@ class SettingsController extends Controller
{
if (!config('app.lock_passwords')) {
if (Input::get('confirm_purge')=='DELETE') {
// Run a backup immediately before processing
Artisan::call('backup:run');
Artisan::call('snipeit:purge', ['--force'=>'true','--no-interaction'=>true]);
$output = Artisan::output();
return view('settings/purge')
+1 -2
View File
@@ -87,9 +87,8 @@ class SuppliersController extends Controller
$supplier->image = $file_name;
}
// Was it created?
if ($supplier->save()) {
// Redirect to the new supplier page
// Redirect to the nw supplier page
return redirect()->route('suppliers.index')->with('success', trans('admin/suppliers/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($supplier->getErrors());
+22 -142
View File
@@ -33,6 +33,7 @@ use URL;
use View;
use Illuminate\Http\Request;
use Gate;
use Artisan;
/**
* This controller handles all actions related to Users for
@@ -370,14 +371,20 @@ class UsersController extends Controller
// Authorize takes care of many of our logic checks now.
$this->authorize('delete', User::class);
if ($user->assets()->count() > 0) {
// Check if we are not trying to delete ourselves
if ($user->id === Auth::user()->id) {
// Redirect to the user management page
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets()->count() . ' assets associated with them.');
}
if (count($user->assets) > 0) {
// Redirect to the user management page
return redirect()->route('users.index')->with('error', 'This user still has ' . count($user->assets) . ' assets associated with them.');
}
if ($user->licenses()->count() > 0) {
// Redirect to the user management page
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->licenses()->count() . ' licenses associated with them.');
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets()->count() . ' assets associated with them.');
}
if ($user->accessories()->count() > 0) {
@@ -532,10 +539,7 @@ class UsersController extends Controller
if (($key = array_search(Auth::user()->id, $user_raw_array)) !== false) {
unset($user_raw_array[$key]);
}
if (!Auth::user()->isSuperUser()) {
return redirect()->route('users.index')->with('error', trans('admin/users/message.insufficient_permissions'));
}
if (!config('app.lock_passwords')) {
@@ -836,7 +840,6 @@ class UsersController extends Controller
'permissions' => '{"user":1}',
'notes' => 'Imported user'
);
//dd($newuser);
DB::table('users')->insert($newuser);
@@ -928,7 +931,6 @@ class UsersController extends Controller
$user = User::find($userId);
$destinationPath = config('app.private_uploads').'/users';
// the license is valid
if (isset($user->id)) {
$this->authorize('update', $user);
$log = Actionlog::find($fileId);
@@ -1028,144 +1030,22 @@ class UsersController extends Controller
*/
public function postLDAP(Request $request)
{
$this->authorize('update', User::class);
ini_set('max_execution_time', 600); //600 seconds = 10 minutes
ini_set('memory_limit', '500M');
// Call Artisan LDAP import command.
$location_id = $request->input('location_id');
Artisan::call('snipeit:ldap-sync', ['--location_id' => $location_id, '--json_summary' => true]);
$ldap_result_username = Setting::getSettings()->ldap_username_field;
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
// Collect and parse JSON summary.
$ldap_results_json = Artisan::output();
$ldap_results = json_decode($ldap_results_json, true);
$ldap_result_active_flag = Setting::getSettings()->ldap_active_flag_field;
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
$ldap_result_email = Setting::getSettings()->ldap_email;
try {
$ldapconn = Ldap::connectToLdap();
} catch (\Exception $e) {
return redirect()->back()->withInput()->with('error', $e->getMessage());
// Direct user to appropriate status page.
if ($ldap_results['error']) {
return redirect()->back()->withInput()->with('error', $ldap_results['error_message']);
} else {
return redirect()->route('ldap/user')->with('success', "LDAP Import successful.")->with('summary', $ldap_results['summary']);
}
try {
Ldap::bindAdminToLdap($ldapconn);
} catch (\Exception $e) {
return redirect()->back()->withInput()->with('error', $e->getMessage());
}
$summary = array();
$ldap_ou_locations = Location::whereNotNull('ldap_ou')->get();
$results = Ldap::findLdapUsers();
// 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];
}
// Delete located users from the general group.
foreach ($results as $key => $generic_entry) {
if (in_array($generic_entry[$ldap_result_username][0], $location_users)) {
unset($results[$key]);
}
}
$global_count = $results['count'];
$results = array_merge($location_users, $results);
$results['count'] = $global_count;
}
$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") {
$item = array();
$item["username"] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : "";
$item["employee_number"] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : "";
$item["lastname"] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : "";
$item["firstname"] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : "";
$item["email"] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : "" ;
$item["ldap_location_override"] = isset($results[$i]["ldap_location_override"]) ? $results[$i]["ldap_location_override"]:"";
$item["location_id"] = isset($results[$i]["location_id"]) ? $results[$i]["location_id"]:"";
if( array_key_exists('useraccountcontrol', $results[$i]) ) {
$enabled_accounts = [
'512', '544', '66048', '66080', '262656', '262688', '328192', '328224'
];
$item['activated'] = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
} else {
$item['activated'] = 0;
}
// User exists
$item["createorupdate"] = 'updated';
if (!$user = User::where('username', $item["username"])->first()) {
$user = new User;
$user->password = $pass;
$item["createorupdate"] = 'created';
}
// Create the user if they don't exist.
$user->first_name = $item["firstname"];
$user->last_name = $item["lastname"];
$user->username = $item["username"];
$user->email = $item["email"];
$user->employee_num = e($item["employee_number"]);
$user->activated = $item['activated'];
if ($item['ldap_location_override'] == true) {
$user->location_id = $item['location_id'];
} else if ($request->input('location_id')!='') {
$user->location_id = e($request->input('location_id'));
}
$user->notes = 'Imported from LDAP';
$user->ldap_import = 1;
$errors = '';
if ($user->save()) {
$item["note"] = $item["createorupdate"];
$item["status"]='success';
} else {
foreach ($user->getErrors()->getMessages() as $key => $err) {
$errors .='<li>'.$err[0];
}
$item["note"] = $errors;
$item["status"]='error';
}
array_push($summary, $item);
}
}
return redirect()->route('ldap/user')->with('success', "LDAP Import successful.")->with('summary', $summary);
}
/**
* Return JSON containing a list of assets assigned to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $userId
* @return string JSON
*/
public function getAssetList($userId)
{
$this->authorize('view', User::class);
$assets = Asset::where('assigned_to', '=', $userId)->with('model')->get();
return response()->json($assets);
}
/**
* Exports users to CSV
@@ -68,8 +68,8 @@ class ViewAssetsController extends Controller
public function getRequestableIndex()
{
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo')->Hardware()->RequestableAssets()->get();
$models = AssetModel::with('category')->RequestableModels()->get();
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo', 'requests')->Hardware()->RequestableAssets()->get();
$models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
return view('account/requestable-assets', compact('user', 'assets', 'models'));
}
+3
View File
@@ -19,10 +19,13 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\FrameGuard::class,
\App\Http\Middleware\XssProtectHeader::class,
\App\Http\Middleware\ReferrerPolicyHeader::class,
\App\Http\Middleware\ContentSecurityPolicyHeader::class,
\App\Http\Middleware\NosniffGuard::class,
\App\Http\Middleware\CheckForSetup::class,
\Fideloper\Proxy\TrustProxies::class,
\App\Http\Middleware\CheckForDebug::class,
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Middleware;
use Closure;
class ContentSecurityPolicyHeader
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
if ((config('app.debug')=='true') || (config('app.enable_csp')!='true')) {
$response = $next($request);
return $response;
}
$policy[] = "default-src 'self'";
$policy[] = "style-src 'self' 'unsafe-inline' oss.maxcdn.com";
$policy[] = "script-src 'self' 'unsafe-inline' oss.mafxcdn.com cdnjs.cloudflare.com 'nonce-".csrf_token()."'";
$policy[] = "connect-src 'self'";
$policy[] = "object-src 'none'";
$policy[] = "font-src 'self' data:";
$policy[] = "img-src 'self' data: gravatar.com";
$policy = join(';', $policy);
$response = $next($request);
$response->headers->set('Content-Security-Policy', $policy);
return $response;
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Closure;
class ReferrerPolicyHeader
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Referrer-Policy', config('app.referrer_policy'));
return $response;
}
}
+2 -1
View File
@@ -14,8 +14,9 @@ class XssProtectHeader
*/
public function handle($request, Closure $next)
{
$mode = '1;mode=block';
$response = $next($request);
$response->headers->set('X-XSS-Protection', '1');
$response->headers->set('X-XSS-Protection', $mode);
return $response;
}
}
+2 -2
View File
@@ -34,14 +34,14 @@ class SaveUserRequest extends Request
case 'POST':
{
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
}
// Save all fields
case 'PUT':
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
// Save only what's passed
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Session;
class SettingsLdapRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url|nullable',
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_version" => 'sometimes|required_if:ldap_enabled,1|nullable',
];
return $rules;
}
public function response(array $errors)
{
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
->put('default', new \Illuminate\Support\MessageBag($errors)));
\Input::flash();
return parent::response($errors);
}
}
@@ -59,13 +59,26 @@ class AccessoriesTransformer
}
public function transformCheckedoutAccessories (Collection $accessories_users, $total)
public function transformCheckedoutAccessory ($accessory_users, $total)
{
$array = array();
foreach ($accessories_users as $user) {
$array[] = (new UsersTransformer)->transformUser($user);
foreach ($accessory_users as $user) {
$array[] = [
'assigned_pivot_id' => $user->pivot->id,
'id' => (int) $user->id,
'username' => e($user->username),
'name' => e($user->getFullNameAttribute()),
'first_name'=> e($user->first_name),
'last_name'=> e($user->last_name),
'employee_number' => e($user->employee_num),
'type' => 'user',
'available_actions' => ['checkin' => true]
];
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
@@ -2,6 +2,7 @@
namespace App\Http\Transformers;
use App\Models\Actionlog;
use App\Models\Setting;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use App\Helpers\Helper;
@@ -12,24 +13,32 @@ class ActionlogsTransformer
public function transformActionlogs (Collection $actionlogs, $total)
{
$array = array();
$settings = Setting::getSettings();
foreach ($actionlogs as $actionlog) {
$array[] = self::transformActionlog($actionlog);
$array[] = self::transformActionlog($actionlog, $settings);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformActionlog (Actionlog $actionlog)
public function transformActionlog (Actionlog $actionlog, $settings = null)
{
$array = [
'id' => (int) $actionlog->id,
'icon' => $actionlog->present()->icon(),
'image' => (method_exists($actionlog->item, 'getImageUrl')) ? $actionlog->item->getImageUrl() : null,
'item' => ($actionlog->item) ? [
'id' => (int) $actionlog->item->id,
'name' => e($actionlog->item->getDisplayNameAttribute()),
'type' => e($actionlog->itemType()),
] : null,
'location' => ($actionlog->location) ? [
'id' => (int) $actionlog->location->id,
'name' => e($actionlog->location->name)
] : 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->item->next_audit_date, 'datetime'): null,
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(), 'date'): null,
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
'action_type' => $actionlog->present()->actionType(),
'admin' => ($actionlog->user) ? [
'id' => (int) $actionlog->user->id,
@@ -43,7 +52,8 @@ class ActionlogsTransformer
'type' => e($actionlog->targetType()),
] : null,
'note' => e($actionlog->note),
'note' => ($actionlog->note) ? e($actionlog->note): null,
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
];
@@ -38,6 +38,7 @@ class AssetMaintenancesTransformer
];
$permissions_array['available_actions'] = [
'update' => (bool) Gate::allows('update', Asset::class),
'delete' => (bool) Gate::allows('delete', Asset::class),
];
@@ -47,13 +47,15 @@ class AssetModelsTransformer
'notes' => e($assetmodel->notes),
'created_at' => Helper::getFormattedDateObject($assetmodel->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($assetmodel->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($assetmodel->deleted_at, 'datetime'),
];
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', AssetModel::class) ? true : false,
'delete' => Gate::allows('delete', AssetModel::class) ? true : false,
'clone' => Gate::allows('create', AssetModel::class) ? true : false,
'update' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', AssetModel::class) && ($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,
];
$array += $permissions_array;
+28 -13
View File
@@ -33,7 +33,8 @@ class AssetsTransformer
'model_number' => ($asset->model) ? e($asset->model->model_number) : null,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name)
'name'=> e($asset->present()->statusText),
'status_meta' => e($asset->present()->statusMeta),
] : null,
'category' => ($asset->model->category) ? [
'id' => (int) $asset->model->category->id,
@@ -53,23 +54,16 @@ class AssetsTransformer
'id' => (int) $asset->company->id,
'name'=> e($asset->company->name)
] : null,
'location' => ($asset->assetLoc) ? [
'id' => (int) $asset->assetLoc->id,
'name'=> e($asset->assetLoc->name)
'location' => ($asset->assetloc) ? [
'id' => (int) $asset->assetloc->id,
'name'=> e($asset->assetloc->name)
] : null,
'rtd_location' => ($asset->defaultLoc) ? [
'id' => (int) $asset->defaultLoc->id,
'name'=> e($asset->defaultLoc->name)
] : null,
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
'assigned_to' => ($asset->assigneduser) ? [
'id' => (int) $asset->assigneduser->id,
'username' => e($asset->assigneduser->username),
'name' => e($asset->assigneduser->getFullNameAttribute()),
'first_name'=> e($asset->assigneduser->first_name),
'last_name'=> e($asset->assigneduser->last_name),
'employee_number' => e($asset->assigneduser->employee_num),
] : null,
'assigned_to' => $this->transformAssignedTo($asset),
'warranty' => ($asset->warranty_months > 0) ? e($asset->warranty_months . ' ' . trans('admin/hardware/form.months')) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
@@ -82,8 +76,9 @@ class AssetsTransformer
];
if ($asset->model->fieldset) {
if (($asset->model->fieldset) && (count($asset->model->fieldset->fields)> 0)) {
$fields_array = array();
foreach ($asset->model->fieldset->fields as $field) {
if ($field->isFieldDecryptable($asset->{$field->convertUnicodeDbSlug()})) {
@@ -130,4 +125,24 @@ class AssetsTransformer
{
return (new DatatablesTransformer)->transformDatatables($assets);
}
public function transformAssignedTo($asset)
{
if ($asset->checkedOutToUser()) {
return $asset->assignedTo ? [
'id' => (int) $asset->assignedTo->id,
'username' => e($asset->assignedTo->username),
'name' => e($asset->assignedTo->getFullNameAttribute()),
'first_name'=> e($asset->assignedTo->first_name),
'last_name'=> e($asset->assignedTo->last_name),
'employee_number' => e($asset->assignedTo->employee_num),
'type' => 'user'
] : null;
}
return $asset->assignedTo ? [
'id' => $asset->assignedTo->id,
'name' => $asset->assignedTo->display_name,
'type' => $asset->assignedType()
] : null;
}
}
@@ -26,7 +26,7 @@ class CategoriesTransformer
'id' => (int) $category->id,
'name' => e($category->name),
'type' => e($category->category_type),
'use_default_eula' => ($category->use_default_eula =='1') ? true : false,
'eula' => ($category->getEula()) ? true : false,
'checkin_email' => ($category->checkin_email =='1') ? true : false,
'require_acceptance' => ($category->require_acceptance =='1') ? true : false,
'assets_count' => $category->assets_count,
@@ -58,12 +58,22 @@ class ComponentsTransformer
}
public function transformCheckedoutComponents(Collection $components_users, $total)
public function transformCheckedoutComponents(Collection $components_assets, $total)
{
$array = array();
foreach ($components_users as $user) {
$array[] = (new UsersTransformer)->transformUser($user);
foreach ($components_assets as $asset) {
$array[] = [
'assigned_pivot_id' => $asset->pivot->id,
'id' => (int) $asset->id,
'name' => e($asset->model->present()->name) .' '.e($asset->present()->name),
'qty' => $asset->pivot->assigned_qty,
'type' => 'asset',
'created_at' => Helper::getFormattedDateObject($asset->pivot->created_at, 'datetime'),
'available_actions' => ['checkin' => true]
];
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
}
@@ -25,7 +25,7 @@ class CustomFieldsTransformer
'name' => e($field->name),
'db_column_name' => e($field->db_column_name()),
'format' => e($field->format),
'required' => $field->pivot->required,
'required' => $field->pivot ? $field->pivot->required : false,
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
];
+1 -1
View File
@@ -23,7 +23,7 @@ class GroupsTransformer
$array = [
'id' => (int) $group->id,
'name' => e($group->name),
'permissions' => $group->permissions,
'permissions' => json_decode($group->permissions),
'users_count' => (int) $group->users_count,
'created_at' => Helper::getFormattedDateObject($group->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($group->updated_at, 'datetime'),
@@ -29,7 +29,6 @@ class ImportsTransformer
'header_row' => $import->header_row,
'first_row' => $import->first_row,
'field_map' => $import->field_map,
];
return $array;
@@ -33,8 +33,9 @@ class LicensesTransformer
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
'notes' => e($license->notes),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'total_seats' => (int) $license->total_seats,
'remaining_qty' => $license->remaincount(),
'total_seats' => (int) $license->seats,
'next_seat' => ($license->freeSeat()) ? (int) $license->freeSeat()->id : null,
'remaining_qty' => (int) $license->remaincount(),
'min_qty' => $license->remaincount(),
'license_name' => e($license->license_name),
'license_email' => e($license->license_email),
@@ -36,9 +36,11 @@ class LocationsTransformer
'address' => e($location->address),
'city' => e($location->city),
'state' => e($location->state),
'assets_checkedout' => $location->assets()->count(),
'assets_default' => $location->assignedassets()->count(),
'country' => e($location->country),
'zip' => e($location->zip),
'assets_checkedout' => $location->location_assets_count,
'assets_default' => $location->assigned_assets_count,
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
'parent' => ($location->parent) ? [
+5 -3
View File
@@ -42,6 +42,7 @@ class UsersTransformer
'id' => (int) $user->userloc->id,
'name'=> e($user->userloc->name)
] : null,
'notes'=> e($user->notes),
'permissions' => $user->decodePermissions(),
'activated' => ($user->activated =='1') ? true : false,
'two_factor_activated' => ($user->two_factor_active()) ? true : false,
@@ -56,9 +57,10 @@ class UsersTransformer
];
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', User::class) ? true : false,
'delete' => Gate::allows('delete', User::class) ? true : false,
'clone' => Gate::allows('create', User::class) ? true : false,
'update' => (Gate::allows('update', User::class) && ($user->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', User::class) && ($user->deleted_at=='')) ? true : false,
'clone' => (Gate::allows('create', User::class) && ($user->deleted_at=='')) ,
'restore' => (Gate::allows('create', User::class) && ($user->deleted_at!='')) ? true : false,
];
$array += $permissions_array;
+12 -6
View File
@@ -23,14 +23,18 @@ class AssetImporter extends ItemImporter
// ItemImporter handles the general fetching.
parent::handle($row);
foreach ($this->customFields as $customField) {
$customFieldValue = $this->array_smart_custom_field_fetch($row, $customField);
if ($customFieldValue) {
$this->item['custom_fields'][$customField->db_column_name()] = $customFieldValue;
$this->log('Custom Field '. $customField->name.': '.$customFieldValue);
if ($this->customFields) {
foreach ($this->customFields as $customField) {
$customFieldValue = $this->array_smart_custom_field_fetch($row, $customField);
if ($customFieldValue) {
$this->item['custom_fields'][$customField->db_column_name()] = $customFieldValue;
$this->log('Custom Field '. $customField->name.': '.$customFieldValue);
}
}
}
$this->createAssetIfNotExists($row);
}
@@ -63,7 +67,9 @@ class AssetImporter extends ItemImporter
$this->item['image'] = $this->findCsvMatch($row, "image");
$this->item['warranty_months'] = intval($this->findCsvMatch($row, "warranty"));
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
if (!$this->item['status_id'] && !$editingAsset) {
// If no status ID is found
if (!array_key_exists('status_id', $this->item) && !$editingAsset) {
$this->log("No status field found, defaulting to first status.");
$this->item['status_id'] = $this->defaultStatusLabelId;
}
+13 -8
View File
@@ -109,7 +109,15 @@ abstract class Importer
{
$headerRow = $this->csv->fetchOne();
$results = $this->normalizeInputArray($this->csv->fetchAssoc());
$this->customFields = CustomField::All(['name']);
// Stolen From https://adamwathan.me/2016/07/14/customizing-keys-when-mapping-collections/
// This 'inverts' the fields such that we have a collection of fields indexed by name.
$cFs = CustomField::All();
$this->customFields = $cFs->reduce(function ($nameLookup, $field) {
$nameLookup[$field['name']] = $field;
return $nameLookup;
});
DB::transaction(function () use (&$results) {
Model::unguard();
$resultsCount = sizeof($results);
@@ -136,14 +144,12 @@ abstract class Importer
* @param $default string
* @return string
*/
public function findCsvMatch(array $array, $key, $default = '')
public function findCsvMatch(array $array, $key, $default = null)
{
$val = $default;
if ($customKey = $this->lookupCustomKey($key)) {
$key = $customKey;
}
$key = $this->lookupCustomKey($key);
$this->log("Custom Key: ${key}");
if (array_key_exists($key, $array)) {
@@ -163,13 +169,12 @@ 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];
}
return null;
// Otherwise no custom key, return original.
return $key;
}
/**
+2 -1
View File
@@ -10,6 +10,7 @@ use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
class ItemImporter extends Importer
{
@@ -68,6 +69,7 @@ class ItemImporter extends Importer
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;
}
}
}
@@ -90,7 +92,6 @@ class ItemImporter extends Importer
$item = collect($this->item);
// First Filter the item down to the model's fillable fields
$item = $item->only($model->getFillable());
// Then iterate through the item and, if we are updating, remove any blank values.
if ($updating) {
$item = $item->reject(function ($value) {
+4 -2
View File
@@ -33,10 +33,12 @@ class LicenseImporter extends ItemImporter
public function createLicenseIfNotExists(array $row)
{
$editingLicense = false;
$license = License::where('name', $this->item['name'])->first();
$license = License::where('name', $this->item['name'])
->where('serial', $this->item['serial'])
->first();
if ($license) {
if (!$this->updating) {
$this->log('A matching License ' . $this->item['name'] . ' already exists');
$this->log('A matching License ' . $this->item['name'] . 'with serial ' . $this->item['serial'] . ' already exists');
return;
}
-1
View File
@@ -61,7 +61,6 @@ class Accessory extends SnipeModel
'purchase_date',
'model_number',
'manufacturer_id',
'notes',
'qty',
'requestable'
];
+32
View File
@@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth;
use Response;
use Carbon;
/**
* Model for the Actionlog (the table that keeps a historical log of
@@ -123,6 +124,10 @@ class Actionlog extends SnipeModel
return $this->belongsTo('\App\Models\ActionLog', 'thread_id');
}
public function location() {
return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed();
}
/**
* Check if the file exists, and if it does, force a download
**/
@@ -149,6 +154,33 @@ class Actionlog extends SnipeModel
}
}
public function daysUntilNextAudit($monthInterval = 12, $asset = null) {
$now = Carbon::now();
$last_audit_date = $this->created_at;
$next_audit = $last_audit_date->addMonth($monthInterval);
$next_audit_days = $now->diffInDays($next_audit);
// Override the default setting for interval if the asset has its own next audit date
if (($asset) && ($asset->next_audit_date)) {
$override_default_next = \Carbon::parse($asset->next_audit_date);
$next_audit_days = $override_default_next->diffInDays($now);
}
return $next_audit_days;
}
public function calcNextAuditDate($monthInterval = 12, $asset = null) {
$last_audit_date = Carbon::parse($this->created_at);
// If there is an asset-specific next date already given,
if (($asset) && ($asset->next_audit_date)) {
return \Carbon::parse($asset->next_audit_date);
}
return \Carbon::parse($last_audit_date)->addMonths($monthInterval)->toDateString();
}
/**
* getListingOfActionLogsChronologicalOrder
*
+89 -73
View File
@@ -1,6 +1,7 @@
<?php
namespace App\Models;
use App\Exceptions\CheckoutNotAllowed;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Presenters\Presentable;
use AssetPresenter;
@@ -10,6 +11,7 @@ use Config;
use Illuminate\Database\Eloquent\SoftDeletes;
use Log;
use Watson\Validating\ValidatingTrait;
use Illuminate\Notifications\Notifiable;
/**
* Model for Assets.
@@ -19,7 +21,7 @@ use Watson\Validating\ValidatingTrait;
class Asset extends Depreciable
{
protected $presenter = 'App\Presenters\AssetPresenter';
use Loggable, Requestable, Presentable;
use Loggable, Requestable, Presentable, Notifiable;
use SoftDeletes;
const LOCATION = 'location';
@@ -66,6 +68,7 @@ class Asset extends Depreciable
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
'status' => 'integer',
'purchase_cost' => 'numeric|nullable',
'next_audit_date' => 'date|nullable',
];
/**
@@ -76,6 +79,7 @@ class Asset extends Depreciable
protected $fillable = [
'asset_tag',
'assigned_to',
'assigned_type',
'company_id',
'image',
'model_id',
@@ -140,7 +144,7 @@ class Asset extends Depreciable
* @return bool
*/
//FIXME: The admin parameter is never used. Can probably be removed.
public function checkOut($target, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
{
if (!$target) {
return false;
@@ -160,50 +164,29 @@ class Asset extends Depreciable
}
if ($this->requireAcceptance()) {
if(get_class($target) != User::class) {
throw new CheckoutNotAllowed;
}
$this->accepted="pending";
}
if ($this->save()) {
$this->logCheckout($note, $target);
// if ((($this->requireAcceptance()=='1') || ($this->getEula())) && ($user->email!='')) {
// $this->checkOutNotifyMail($log->id, $user, $checkout_at, $expected_checkin, $note);
// }
return true;
}
return false;
}
public function checkOutNotifyMail($log_id, $user, $checkout_at, $expected_checkin, $note)
{
$data['log_id'] = $log_id;
$data['eula'] = $this->getEula();
$data['first_name'] = $user->first_name;
$data['item_name'] = $this->present()->name();
$data['checkout_date'] = $checkout_at;
$data['expected_checkin'] = $expected_checkin;
$data['item_tag'] = $this->asset_tag;
$data['note'] = $note;
$data['item_serial'] = $this->serial;
$data['require_acceptance'] = $this->requireAcceptance();
if ((($this->requireAcceptance()=='1') || ($this->getEula())) && (!config('app.lock_passwords'))) {
\Mail::send('emails.accept-asset', $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.Confirm_asset_delivery'));
});
}
}
public function getDetailedNameAttribute()
{
if ($this->assignedTo) {
$user_name = $this->assignedTo->present()->name();
if ($this->assignedto) {
$user_name = $this->assignedto->present()->name();
} else {
$user_name = "Unassigned";
}
return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . $this->model->name;
}
public function validationRules($id = '0')
{
return $this->rules;
@@ -246,16 +229,14 @@ class Asset extends Depreciable
->orderBy('created_at', 'desc');
}
/**
* Even though we allow allow for checkout to things beyond users
* this method is an easy way of seeing if we are checked out to a user.
* @return mixed
*/
public function assigneduser()
public function checkedOutToUser()
{
return $this->belongsTo('\App\Models\User', 'assigned_to')
->withTrashed();
return $this->assignedType() === self::USER;
}
public function assignedTo()
@@ -274,19 +255,20 @@ class Asset extends Depreciable
public function assetLoc()
{
if (!empty($this->assignedType())) {
// dd($this->assignedType());
if ($this->assignedType() == self::ASSET) {
return $this->assignedTo->assetloc(); // Recurse until we have a final location
return $this->assignedto->assetloc(); // Recurse until we have a final location
}
if ($this->assignedType() == self::LOCATION) {
return $this->assignedTo();
} elseif (!$this->assignedTo) {
return $this->defaultLoc();
} elseif ($this->assignedType() == self::USER) {
return $this->assignedTo->userLoc();
}
if ($this->assignedType() == self::USER) {
if (!$this->assignedTo) {
return $this->defaultLoc();
}
return $this->assignedTo->userLoc();
}
}
return $this->defaultLoc();
}
@@ -505,7 +487,7 @@ class Asset extends Depreciable
} elseif ($this->model->category->use_default_eula == '1') {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
return false;
}
}
@@ -548,7 +530,7 @@ class Asset extends Depreciable
/**
* Query builder scope for pending assets
* Query builder scope for searching location
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
*
@@ -558,8 +540,17 @@ class Asset extends Depreciable
public function scopeAssetsByLocation($query, $location)
{
return $query->where(function ($query) use ($location) {
$query->whereHas('assigneduser', function ($query) use ($location) {
$query->where('users.location_id', '=', $location->id);
$query->whereHas('assignedTo', function ($query) use ($location) {
$query->where([
['users.location_id', '=', $location->id],
['assets.assigned_type', '=', User::class]
])->orWhere([
['locations.id', '=', $location->id],
['assets.assigned_type', '=', Location::class]
])->orWhere([
['assets.rtd_location_id', '=', $location->id],
['assets.assigned_type', '=', Asset::class]
]);
})->orWhere(function ($query) use ($location) {
$query->where('assets.rtd_location_id', '=', $location->id);
$query->whereNull('assets.assigned_to');
@@ -735,7 +726,8 @@ class Asset extends Depreciable
/**
* Query builder scope to search on text for complex Bootstrap Tables API
* Query builder scope to search on text for complex Bootstrap Tables API.
* This is really horrible, but I can't think of a less-awful way to do it.
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $search Search term
@@ -746,7 +738,16 @@ class Asset extends Depreciable
{
$search = explode(' OR ', $search);
return $query->where(function ($query) use ($search) {
return $query->leftJoin('users',function ($leftJoin) {
$leftJoin->on("users.id", "=", "assets.assigned_to")
->where("assets.assigned_type", "=", User::class);
})->leftJoin('locations',function ($leftJoin) {
$leftJoin->on("locations.id","=","assets.assigned_to")
->where("assets.assigned_type","=",Location::class);
})->leftJoin('assets as assigned_assets',function ($leftJoin) {
$leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to')
->where('assets.assigned_type', '=', Asset::class);
})->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('model', function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
@@ -779,18 +780,12 @@ class Asset extends Depreciable
$query->whereHas('defaultLoc', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assigneduser', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('users.last_name', 'LIKE', '%'.$search.'%')
->orWhere(function ($query) use ($search) {
$query->whereHas('userloc', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
});
});
});
})->orWhere(function ($query) use ($search) {
$query->where('users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('users.last_name', 'LIKE', '%'.$search.'%')
->orWhere('users.username', 'LIKE', '%'.$search.'%')
->orWhere('locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');
})->orWhere('assets.name', 'LIKE', '%'.$search.'%')
->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%')
->orWhere('assets.serial', 'LIKE', '%'.$search.'%')
@@ -798,9 +793,9 @@ class Asset extends Depreciable
->orWhere('assets.notes', 'LIKE', '%'.$search.'%');
}
foreach (CustomField::all() as $field) {
$query->orWhere($field->db_column_name(), 'LIKE', "%$search%");
$query->orWhere('assets.'.$field->db_column_name(), 'LIKE', "%$search%");
}
});
})->withTrashed()->whereNull("assets.deleted_at"); //workaround for laravel bug
}
@@ -817,6 +812,7 @@ class Asset extends Depreciable
{
return $query->where(function ($query) use ($filter) {
foreach ($filter as $key => $search_val) {
if ($key =='asset_tag') {
$query->where('assets.asset_tag', 'LIKE', '%'.$search_val.'%');
}
@@ -858,10 +854,10 @@ class Asset extends Depreciable
}
if ($key =='checkedout_to') {
$query->whereHas('assigneduser', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('users.first_name', 'LIKE', '%' . $search . '%')
->orWhere('users.last_name', 'LIKE', '%' . $search . '%');
$query->whereHas('assigneduser', function ($query) use ($search_val) {
$query->where(function ($query) use ($search_val) {
$query->where('users.first_name', 'LIKE', '%' . $search_val . '%')
->orWhere('users.last_name', 'LIKE', '%' . $search_val . '%');
});
});
}
@@ -878,8 +874,8 @@ class Asset extends Depreciable
}
if ($key =='category') {
$query->whereHas('model', function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
$query->whereHas('model', function ($query) use ($search_val) {
$query->whereHas('category', function ($query) use ($search_val) {
$query->where(function ($query) use ($search_val) {
$query->where('categories.name', 'LIKE', '%' . $search_val . '%')
->orWhere('models.name', 'LIKE', '%' . $search_val . '%')
@@ -916,11 +912,13 @@ class Asset extends Depreciable
}
foreach (CustomField::all() as $field) {
if (array_key_exists($field->db_column_name(), $filter)) {
$query->orWhere($field->db_column_name(), 'LIKE', "%$search_val%");
}
if (array_key_exists('custom_fields.'.$field->db_column_name(), $filter)) {
$query->orWhere($field->db_column_name(), 'LIKE', '%' . $search_val . '%');
}
}
});
}
@@ -1093,13 +1091,31 @@ class Asset extends Depreciable
$query->whereHas('defaultLoc', function ($query) use ($search) {
$query->where('locations.id', '=', $search);
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assigneduser', function ($query) use ($search) {
$query->whereHas('userloc', function ($query) use ($search) {
$query->where('locations.id', '=', $search);
});
});
});
// FIXME: This needs porting to checkout to non-user.
// ->orWhere(function ($query) use ($search) {
// $query->whereHas('assigneduser', function ($query) use ($search) {
// $query->whereHas('userloc', function ($query) use ($search) {
// $query->where('locations.id', '=', $search);
// });
// });
// });
}
/**
* Query builder scope to search on location ID
*
* @param \Illuminate\Database\Query\Builder $query Query builder instance
* @param text $search Search term
*
* @return \Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeByDepreciationId($query, $search)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')
->join('depreciations', 'models.depreciation_id', '=', 'depreciations.id')->where('models.depreciation_id', '=', $search);
}
+1 -1
View File
@@ -29,7 +29,7 @@ class AssetMaintenance extends Model implements ICompanyableChild
'title' => 'required|max:100',
'is_warranty' => 'boolean',
'start_date' => 'required|date_format:"Y-m-d"',
'completion_date' => 'date_format:"Y-m-d"',
'completion_date' => 'nullable|date_format:"Y-m-d"',
'notes' => 'string|nullable',
'cost' => 'numeric|nullable'
];
+4 -4
View File
@@ -26,7 +26,7 @@ class AssetModel extends SnipeModel
// Declare the rules for the model validation
protected $rules = array(
'name' => 'required|min:1|max:255',
'model_number' => 'min:1|max:255',
'model_number' => 'max:255|nullable',
'category_id' => 'required|integer|exists:categories,id',
'manufacturer_id' => 'required|integer|exists:manufacturers,id',
'eol' => 'integer:min:0|max:240|nullable',
@@ -153,17 +153,17 @@ class AssetModel extends SnipeModel
->orWhere('model_number', 'LIKE', "%$search%")
->orWhere(function ($query) use ($search) {
$query->whereHas('depreciation', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
$query->where('depreciations.name', 'LIKE', '%'.$search.'%');
});
})
->orWhere(function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
$query->where('categories.name', 'LIKE', '%'.$search.'%');
});
})
->orWhere(function ($query) use ($search) {
$query->whereHas('manufacturer', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
});
});
+2 -1
View File
@@ -53,6 +53,7 @@ class Component extends SnipeModel
'name',
'purchase_cost',
'purchase_date',
'min_amt',
'qty',
];
@@ -63,7 +64,7 @@ class Component extends SnipeModel
public function assets()
{
return $this->belongsToMany('\App\Models\Asset', 'components_assets')->withPivot('assigned_qty', 'created_at', 'user_id');
return $this->belongsToMany('\App\Models\Asset', 'components_assets')->withPivot('id', 'assigned_qty', 'created_at', 'user_id');
}
public function admin()
+1 -1
View File
@@ -73,7 +73,7 @@ class Consumable extends SnipeModel
return $this->belongsTo('\App\Models\User', 'user_id');
}
public function consumableAssigments()
public function consumableAssignments()
{
return $this->hasMany('\App\Models\ConsumableAssignment');
}
+10 -1
View File
@@ -62,9 +62,18 @@ class CustomField extends Model
return true;
}
return Schema::table(CustomField::$table_name, function ($table) use ($custom_field) {
$platform = Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('enum', 'string');
Schema::table(CustomField::$table_name, function ($table) use ($custom_field) {
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal("name")), $custom_field->convertUnicodeDbSlug());
});
$custom_field->db_column = $custom_field->convertUnicodeDbSlug();
$custom_field->save();
return true;
}
return true;
});
+1 -3
View File
@@ -47,9 +47,7 @@ class CustomFieldset extends Model
if (($field->field_encrypted!='1') ||
(($field->field_encrypted =='1') && (Gate::allows('admin')) )) {
if ($field->pivot->required) {
$rule[]="required";
}
$rule[] = ($field->pivot->required=='1') ? "required" : "nullable";
}
array_push($rule, $field->attributes['format']);
+17
View File
@@ -36,4 +36,21 @@ class Group extends SnipeModel
{
return json_decode($this->permissions, true);
}
/**
* Query builder scope to search on text
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $search Search term
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeTextSearch($query, $search)
{
return $query->where(function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
});
}
}
+7 -9
View File
@@ -48,6 +48,7 @@ class Ldap extends Model
// Needed for AD
ldap_set_option($connection, LDAP_OPT_REFERRALS, 0);
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
if ($ldap_use_tls=='1') {
ldap_start_tls($connection);
@@ -76,25 +77,22 @@ class Ldap extends Model
$connection = Ldap::connectToLdap();
$ldap_username_field = $settings->ldap_username_field;
$baseDn = $settings->ldap_basedn;
$userDn = $ldap_username_field.'='.$username.','.$settings->ldap_basedn;
if ($settings->is_ad =='1') {
// Check if they are using the userprincipalname for the username field.
// Check if they are using the userprincipalname for the username field.
// If they are, we can skip building the UPN to authenticate against AD
if ($ldap_username_field=='userprincipalname') {
$userDn = $username;
} else {
// In case they haven't added an AD domain
if ($settings->ad_domain == '') {
$userDn = $username.'@'.$settings->email_domain;
} else {
$userDn = $username.'@'.$settings->ad_domain;
}
$userDn = ($settings->ad_domain != '') ? $username.'@'.$settings->ad_domain : $username.'@'.$settings->email_domain;
}
} else {
$userDn = $ldap_username_field.'='.$username.','.$settings->ldap_basedn;
}
\Log::debug('Attempting to login using distinguished name:'.$userDn);
$filterQuery = $settings->ldap_auth_filter_query . $username;
@@ -110,7 +108,7 @@ class Ldap extends Model
return false;
}
if (!$user = array_change_key_case(ldap_get_attributes($connection, $entry), CASE_LOWER)) {
if (!$user = ldap_get_attributes($connection, $entry)) {
return false;
}
+9 -6
View File
@@ -31,10 +31,10 @@ class License extends Depreciable
protected $rules = array(
'name' => 'required|string|min:3|max:255',
'seats' => 'required|min:1|max:1000000|integer',
'license_email' => 'email|min:0|max:120',
'license_name' => 'string|min:0|max:100',
'note' => 'string',
'notes' => 'string|min:0',
'license_email' => 'email|nullable|max:120',
'license_name' => 'string|nullable|max:100',
'note' => 'string|nullable',
'notes' => 'string|nullable',
'company_id' => 'integer|nullable',
);
@@ -332,14 +332,17 @@ class License extends Depreciable
return $this->belongsTo('\App\Models\Supplier', 'supplier_id');
}
/*
* Get the next available free seat - used by
* the API to populate next_seat
*/
public function freeSeat()
{
$seat = LicenseSeat::where('license_id', '=', $this->id)
return $this->licenseseats()
->whereNull('deleted_at')
->whereNull('assigned_to')
->whereNull('asset_id')
->first();
return $seat->id;
}
public static function getExpiringLicenses($days = 60)
+5
View File
@@ -83,6 +83,11 @@ class Location extends SnipeModel
// return $this->hasMany('\App\Models\Asset', 'assigned_to')->withTrashed();
}
public function setLdapOuAttribute($ldap_ou)
{
return $this->attributes['ldap_ou'] = empty($ldap_ou) ? null : $ldap_ou;
}
public static function getLocationHierarchy($locations, $parent_id = null)
{
+55 -48
View File
@@ -30,11 +30,59 @@ trait Loggable
* @since [v3.4]
* @return \App\Models\Actionlog
*/
public function logCheckout($note, $target = null /*target is overridable for components*/)
public function logCheckout($note, $target /* What are we checking out to? */)
{
$log = new Actionlog;
$log = $this->determineLogItemType($log);
$log->user_id = Auth::user()->id;
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :)
if (!isset($target)) {
throw new Exception('All checkout logs require a target');
return;
}
$log->target_type = get_class($target);
$log->target_id = $target->id;
$target_class = get_class($target);
// Figure out what the target is
if ($target_class == Location::class) {
// We can checkout to a location
$log->location_id = $target->id;
} elseif ($target_class== Asset::class) {
$log->location_id = $target->rtd_location_id;
} else {
$log->location_id = $target->location_id;
}
$log->note = $note;
$log->logaction('checkout');
$params = [
'item' => $log->item,
'target' => $target,
'admin' => $log->user,
'note' => $note,
'log_id' => $log->id
];
if ($settings = Setting::getSettings()) {
$settings->notify(new CheckoutNotification($params));
}
if (method_exists($target, 'notify')) {
$target->notify(new CheckoutNotification($params));
}
return $log;
}
/**
* Helper method to determine the log item type
*/
private function determineLogItemType($log)
{
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :
if (static::class == LicenseSeat::class) {
$log->item_type = License::class;
$log->item_id = $this->license_id;
@@ -43,52 +91,8 @@ trait Loggable
$log->item_id = $this->id;
}
$log->user_id = Auth::user()->id;
// @FIXME This needs to be generalized with new asset checkout.
if(isset($target)) {
$log->target_type = get_class($target);
$log->target_id = $target->id;
} else {
if (!is_null($this->asset_id)) {
$log->target_type = Asset::class;
$log->target_id = $this->asset_id;
} elseif (!is_null($this->assigned_to)) {
$log->target_type = User::class;
$log->target_id = $this->assigned_to;
}
}
$item = call_user_func(array($log->target_type, 'find'), $log->target_id);
if($this->assignedTo) {
$item = $this->assignedTo;
}
$class = get_class($item);
if($class == Location::class) {
// We can checkout to a location
$log->location_id = $item->id;
} else if ($class== Asset::class) {
$log->location_id = $item->rtd_location_id;
} else {
$log->location_id = $item->location_id;
}
$log->note = $note;
$log->logaction('checkout');
$params = [
'item' => $log->item,
'target' => $log->target,
'admin' => $log->user,
'note' => $note
];
if ($settings = Setting::getSettings()) {
$settings->notify(new CheckoutNotification($params));
}
return $log;
}
/**
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
* @since [v3.4]
@@ -127,9 +131,10 @@ trait Loggable
* @since [v4.0]
* @return \App\Models\Actionlog
*/
public function logAudit($note)
public function logAudit($note, $location_id)
{
$log = new Actionlog;
$location = Location::find($location_id);
if (static::class == LicenseSeat::class) {
$log->item_type = License::class;
$log->item_id = $this->license_id;
@@ -137,7 +142,7 @@ trait Loggable
$log->item_type = static::class;
$log->item_id = $this->id;
}
$log->location_id = null;
$log->location_id = ($location_id) ? $location_id : null;
$log->note = $note;
$log->user_id = Auth::user()->id;
$log->logaction('audit');
@@ -145,6 +150,7 @@ trait Loggable
$params = [
'item' => $log->item,
'admin' => $log->user,
'location' => ($location) ? $location->name : '',
'note' => $note
];
Setting::getSettings()->notify(new AuditNotification($params));
@@ -153,6 +159,7 @@ trait Loggable
}
/**
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
* @since [v3.5]
+3 -3
View File
@@ -19,9 +19,9 @@ trait Requestable
public function isRequestedBy(User $user)
{
return $this->requests()
->where('user_id', $user->id)
->exists();
$requests = $this->requests->where('user_id', $user->id);
return $requests->count() > 0;
}
public function scopeRequestedBy($query, User $user)
+2 -9
View File
@@ -34,17 +34,10 @@ class Setting extends Model
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url|nullable',
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable',
"ldap_version" => 'sometimes|required_if:ldap_enabled,1|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",
];
protected $fillable = ['site_name','email_domain','email_format','username_format'];
+19
View File
@@ -77,6 +77,25 @@ class SnipeModel extends Model
return;
}
public function setMinAmtAttribute($value)
{
if ($value == '') {
$value = null;
}
$this->attributes['min_amt'] = $value;
return;
}
public function setParentIdAttribute($value)
{
if ($value == '') {
$value = null;
}
$this->attributes['parent_id'] = $value;
return;
}
//
public function getDisplayNameAttribute()
{
+1 -1
View File
@@ -21,7 +21,7 @@ class Statuslabel extends SnipeModel
protected $rules = array(
'name' => 'required|string|unique_undeleted',
'notes' => 'string',
'notes' => 'string|nullable',
'deployable' => 'required',
'pending' => 'required',
'archived' => 'required',
+12 -12
View File
@@ -15,18 +15,18 @@ class Supplier extends SnipeModel
protected $rules = array(
'name' => 'required|min:3|max:255|unique_undeleted',
'address' => 'min:3|max:50',
'address2' => 'min:2|max:50',
'city' => 'min:3|max:255',
'state' => 'min:0|max:32',
'country' => 'min:0|max:2',
'fax' => 'min:7|max:35',
'phone' => 'min:7|max:35',
'contact' => 'min:0|max:100',
'notes' => 'min:0|max:255',
'email' => 'email|min:5|max:150',
'zip' => 'min:0|max:10',
'url' => 'min:3|max:250',
'address' => 'max:50|nullable',
'address2' => 'max:50|nullable',
'city' => 'max:255|nullable',
'state' => 'max:32|nullable',
'country' => 'max:3|nullable',
'fax' => 'min:7|max:35|nullable',
'phone' => 'min:7|max:35|nullable',
'contact' => 'max:100|nullable',
'notes' => 'max:255|nullable',
'email' => 'email|max:150|nullable',
'zip' => 'max:10|nullable',
'url' => 'sometimes|nullable|string|max:250',
);
/**
+8
View File
@@ -378,6 +378,14 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
return json_decode($this->permissions, true);
}
public function scopeByGroup($query, $id) {
return $query->whereHas('groups', function ($query) use ($id) {
$query->where('id', '=', $id);
});
}
/**
* Query builder scope to search on text
*
+3 -5
View File
@@ -56,8 +56,9 @@ class AuditNotification extends Notification
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->present()->fullName().'>'
];
array_key_exists('note', $this->params) && $fields['Notes'] = $this->params['note'];
array_key_exists('location', $this->params) && $fields['Location'] = $this->params['location'];
$attachment->title($item->name, $item->present()->viewUrl())
$attachment->title($item->present()->name, $item->present()->viewUrl())
->fields($fields);
});
}
@@ -69,10 +70,7 @@ class AuditNotification extends Notification
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', 'https://laravel.com')
->line('Thank you for using our application!');
}
/**
+6 -4
View File
@@ -41,10 +41,12 @@ class CheckinNotification extends Notification
$notifyBy[] = 'slack';
}
$item = $this->params['item'];
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
if (class_basename(get_class($this->params['item']))=='Asset') {
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance() == '1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
}
}
return $notifyBy;
}
+43 -10
View File
@@ -5,10 +5,11 @@ namespace App\Notifications;
use App\Models\Setting;
use App\Models\SnipeModel;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class CheckoutNotification extends Notification
{
@@ -43,10 +44,12 @@ class CheckoutNotification extends Notification
}
$item = $this->params['item'];
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
if (class_basename(get_class($this->params['item']))=='Asset') {
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance() == '1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
}
}
return $notifyBy;
}
@@ -79,10 +82,40 @@ class CheckoutNotification extends Notification
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', 'https://laravel.com')
->line('Thank you for using our application!');
if (class_basename(get_class($this->params['item']))=='Asset') {
//TODO: Expand for non assets.
$item = $this->params['item'];
$admin_user = $this->params['admin'];
$target = $this->params['target'];
$data = [
'eula' => method_exists($item, 'getEula') ? $item->getEula() : '',
'first_name' => $target->present()->fullName(),
'item_name' => $item->present()->name(),
'checkout_date' => $item->last_checkout,
'expected_checkin' => $item->expected_checkin,
'item_tag' => $item->asset_tag,
'note' => $this->params['note'],
'item_serial' => $item->serial,
'require_acceptance' => method_exists($item, 'requireAcceptance') ? $item->requireAcceptance() : '',
'log_id' => $this->params['log_id'],
'manufacturer_name' => $item->model->manufacturer->name,
'model_name' => $item->model->name,
'model_number' => $item->model->model_number,
];
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance() == '1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
return (new MailMessage)
->view('emails.accept-asset', $data)
->subject(trans('mail.Confirm_asset_delivery'));
}
}
}
/**
@@ -0,0 +1,86 @@
<?php
namespace App\Notifications;
use App\Models\Setting;
use App\Models\SnipeModel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
use Carbon\Carbon;
class ExpectedCheckinNotification extends Notification
{
use Queueable;
/**
* @var
*/
private $params;
/**
* Create a new notification instance.
*
* @param $params
*/
public function __construct($params)
{
$this->params = $params;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
$notifyBy = [];
$item = $this->params['item'];
$notifyBy[]='mail';
return $notifyBy;
}
public function toSlack($notifiable)
{
}
/**
* Get the mail representation of the notification.
*
* @param mixed $asset
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($params)
{
$formatted_due = Carbon::parse($this->params->expected_checkin)->format('D, M j, Y');
return (new MailMessage)
->error()
->subject('Reminder: '.$this->params->present()->name().' checkin deadline approaching')
->line('Hi, '.$this->params->assignedto->first_name)
->greeting('An asset checked out to you is due to be checked back in on '.$formatted_due.'.')
->line('Asset: '.$this->params->present()->name())
->line('Serial: '.$this->params->serial)
->line('Asset Tag: '.$this->params->asset_tag)
->action('View Your Assets', route('view-assets'));
}
/**
* 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