Compare commits

..

514 Commits

Author SHA1 Message Date
snipe
6008eec205 Merge branch 'develop' 2017-11-02 04:37:27 -07:00
snipe
3343cf16dd Bumped version 2017-11-02 04:37:08 -07:00
snipe
48207fc695 Added model number in box header 2017-11-02 04:36:04 -07:00
snipe
3dae464c34 Added nicer formatting for model details 2017-11-02 04:33:53 -07:00
snipe
0c524e0830 Use model image if it’s a requestable model 2017-11-02 04:29:05 -07:00
snipe
da56a253bc Added checkout requests method 2017-11-02 04:21:57 -07:00
snipe
a844d5b018 Added pagination, nicer formatting for requested assets 2017-11-02 04:17:14 -07:00
snipe
ba9bb470eb Added imageSrc presenter to assets 2017-11-02 04:15:24 -07:00
snipe
41452450b3 Added imageSrc presenter 2017-11-02 04:15:09 -07:00
snipe
a9e5ad0df1 Added link to requested assets in sidenav 2017-11-02 03:12:12 -07:00
snipe
0e2f4f3cfb Added requested route back in 2017-11-02 03:11:09 -07:00
snipe
3bc9d3f3f1 Merge branch 'develop' 2017-11-01 23:47:36 -07:00
snipe
81ca0ac91d Added better styling for user upload 2017-11-01 23:46:21 -07:00
snipe
3ca5d39c66 Hide upload button if app is locked 2017-11-01 23:44:31 -07:00
snipe
4f008e118f Fixed search string on suppliers selectlist 2017-11-01 21:55:17 -07:00
snipe
e11f9313f0 Fixed #4360 - better output if backup fails 2017-11-01 14:12:18 -07:00
snipe
d379c6b61f Merge branch 'develop' 2017-11-01 13:28:19 -07:00
snipe
d36e8cfbd2 Dashbpoard pie fixes 2017-11-01 13:27:59 -07:00
snipe
4cdcbc97ee Fixed varname issue on old image delete for manufacturers 2017-11-01 13:10:56 -07:00
snipe
ba516ac9af Merge branch 'develop' 2017-11-01 11:11:32 -07:00
snipe
feb2f5b076 Fixed #4356 - removed reference to old assetloc 2017-10-31 18:20:03 -07:00
snipe
b5f1e10b45 Merge branch 'develop' 2017-10-31 11:50:47 -07:00
snipe
a1eac967a7 Few more migration fixes 2017-10-31 08:57:57 -07:00
snipe
6186c324b5 Misc assetLoc error checks 2017-10-31 08:47:40 -07:00
snipe
772785f9b5 Few more fixes for big ugly location migration 2017-10-31 08:39:53 -07:00
snipe
2f6c0cee59 Merge branch 'develop' 2017-10-31 07:46:36 -07:00
snipe
e56f1ee6fd Fix for anomolies where asigned_type is not null but asigned_to is 2017-10-31 07:33:43 -07:00
snipe
37868cd70e Added warranty and expiration to list view 2017-10-31 07:05:15 -07:00
snipe
32b2f77ad9 Fixed issue where we tried to call the audit log even if the asset wasn’t valid 2017-10-31 05:41:06 -07:00
snipe
472a5b9f69 Removed extra log on API asset create 2017-10-31 05:38:52 -07:00
snipe
121e158f39 Change method name from userloc to location
This needs to be changed in more places though
2017-10-31 05:22:57 -07:00
snipe
f4e7bfc28d Null custom field if field exists but is empty 2017-10-31 05:22:21 -07:00
snipe
0089f73686 Moved trait to single line 2017-10-31 05:21:55 -07:00
snipe
0f4c05c5d0 Remove commented code 2017-10-31 05:02:46 -07:00
snipe
379274deff Check for multiple variable (for bulk checkout) 2017-10-31 04:48:40 -07:00
snipe
dbf5fec7b0 Fixed language string 2017-10-31 04:48:09 -07:00
snipe
4bb546a882 Pull assigned asets preview into its own blade for re-use 2017-10-31 04:47:59 -07:00
snipe
7f1b7be416 Rolling back prepending models to sort 2017-10-30 21:26:25 -07:00
snipe
02720f225c Fixed sorting issue in asset models when ordering by manufacturer 2017-10-30 20:51:01 -07:00
snipe
e44e573a3c Fixed requestable assets reference to assetloc 2017-10-30 19:40:35 -07:00
snipe
546c3e50fa Fixed updating the assigned assets location if user’s location changes 2017-10-30 19:33:52 -07:00
snipe
7f1b962e56 Improved use of de-normed locations fields 2017-10-30 19:21:35 -07:00
snipe
4eee7f8d97 Added address for users - fixes #4323 2017-10-30 18:57:00 -07:00
snipe
0fd0e3a8b4 Returns null for order number if it’s blank 2017-10-28 15:53:22 -07:00
snipe
1076ec96be Bumped version 2017-10-28 15:46:02 -07:00
snipe
3b498efee1 Fixes indefined item in user select blade 2017-10-28 15:42:55 -07:00
snipe
9687a78981 Fixed a few inconsistencies in the API results (null vs empty string) 2017-10-28 15:17:36 -07:00
snipe
2244a4b3cf Fix peresenter for assigned 2017-10-28 15:17:09 -07:00
snipe
f3f84f1a8c Production assets 2017-10-28 11:22:38 -07:00
snipe
41994c95e0 Bumped version 2017-10-28 11:22:27 -07:00
snipe
39c68214e9 More ajax menu fixes 2017-10-28 11:17:52 -07:00
snipe
9c94e70917 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-28 09:21:49 -07:00
snipe
6a3716a06d Added new ajax dropdown menus for components, consumables, etc editing/creating 2017-10-28 09:21:39 -07:00
Sorvani
feccc55c54 Added support for Fedora to the installer. (#4332) 2017-10-28 09:17:19 -07:00
snipe
fe70792cbd Bumped hash 2017-10-28 08:41:34 -07:00
snipe
95b6e0d2d8 Fixed assetloc to location 2017-10-28 08:40:27 -07:00
snipe
5d890fb139 Added more defaults for selected values 2017-10-28 08:38:19 -07:00
snipe
cd2816b1c7 Suppliers ajax menu API route 2017-10-28 08:38:00 -07:00
snipe
2172e6cc25 Added suppliers ajax list 2017-10-28 08:37:47 -07:00
snipe
04130a568c Fixes check for help_text 2017-10-28 07:41:13 -07:00
snipe
108ac79442 Added update to asset location id on checkout/checkin 2017-10-28 07:38:36 -07:00
snipe
3d7fd5cf04 Fixed references to assetLoc in hardware view 2017-10-28 07:29:32 -07:00
snipe
5737de2e22 Added help text to location partial 2017-10-28 07:29:14 -07:00
snipe
1e21cef218 Set max page size to 500 2017-10-28 07:29:03 -07:00
snipe
ad7a2da9bd Add help text that explains location override 2017-10-28 07:28:49 -07:00
snipe
bd48ae96c2 Update location on checkin if one is given 2017-10-28 07:28:35 -07:00
snipe
0f5e0dcd4f Added nobr for nicer formatting of bs tables status and deployed to 2017-10-28 07:12:47 -07:00
snipe
c37fa44f72 Use ther morphto assigned 2017-10-28 07:12:22 -07:00
snipe
daaf98783f Fixes status display in listing 2017-10-28 07:11:06 -07:00
snipe
1399ebb133 Nicer formatting on 503 2017-10-28 07:01:45 -07:00
snipe
03f6211582 Make notes null if empty 2017-10-28 07:01:06 -07:00
snipe
20bcc73000 Don’t emit to logs on this migration, otherwise we’ll flood the actionlogs 2017-10-28 06:33:15 -07:00
snipe
0058f02e82 Closure wasn’t working, go traditional 2017-10-28 06:23:04 -07:00
snipe
25b8c4438e Check for asset before attempting to cite mismatch 2017-10-28 06:20:44 -07:00
snipe
4f1747023a Seed with demo images 2017-10-28 05:46:43 -07:00
snipe
46fb5c9d40 Remove die() from migration 2017-10-28 03:54:06 -07:00
snipe
52f10232a1 Merge branch 'features/flatten-locations' into develop 2017-10-28 03:50:32 -07:00
snipe
5278dac2b0 Eager loading assignedTo - I have no idea why this works 2017-10-28 03:50:02 -07:00
snipe
890012f6c4 Update references to assetloc to location 2017-10-28 02:58:38 -07:00
snipe
3991f79115 Use new location method for hardware view 2017-10-28 02:37:59 -07:00
snipe
0a114c7daf Log instead of echoing 2017-10-28 02:32:05 -07:00
snipe
3064b3f80e Updated availableForCheckout() method to be clearer 2017-10-28 02:31:54 -07:00
snipe
df430a2263 Removed assignedTo eager load for now - it’s not working 2017-10-28 02:31:36 -07:00
snipe
277e49468b Added deleted at to API 2017-10-28 02:31:13 -07:00
snipe
f687c8db24 Fix custom field seeder to drop old columns 2017-10-28 02:11:10 -07:00
snipe
c616041876 Use form selector 2017-10-28 01:51:10 -07:00
snipe
d76f858dcd Try eager loading assignedTo 2017-10-28 01:50:58 -07:00
snipe
7a543fa6d5 Use new location method on asset API 2017-10-28 01:49:13 -07:00
snipe
49afd325a9 Add more data from seeders to check for 1001 queries 2017-10-28 01:48:50 -07:00
snipe
ce5ccc31f0 Added location method, fixed assetLoc 2017-10-28 01:48:27 -07:00
snipe
c70db75de9 Migration to add location_id de-normed data 2017-10-28 01:47:59 -07:00
snipe
7b76bbfd68 Update seeders with more locations 2017-10-28 01:03:16 -07:00
snipe
cfd1925625 Nicer display of notifications on checkout 2017-10-28 01:00:26 -07:00
snipe
e8b4bdf6f4 Added location_id to assets table to denorm 2017-10-27 20:35:34 -07:00
snipe
7e0c33d535 Speed up user factory by only bcrypting once 2017-10-27 20:35:13 -07:00
tiagom62
24211cb674 Setup firewall rules on CentOS 7. (#4329) 2017-10-27 18:27:44 -07:00
snipe
2d758be0e1 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-27 18:01:46 -07:00
snipe
f49ecbdb61 Code cleanup 2017-10-27 18:01:42 -07:00
Daniel Meltzer
3cea12565b Add missing policies (#4330)
* Add Authorizable trait and interface to our user model so we have access to User::can/User::cant.  We should take a look at where else our user model has diverged from Larvel since it was created...

* Policy cleanup/fixes.

This commit adds policies for the missing backend/"settings" areas.  The
permissions were implemented a while back but the policies did not, so
authorizing actions was failing.

In addition, this condenses a lot of code in the policies into base
classes.  Most of the files were identical except for table names, so we
move all of the checks into a base class and override the table name in
each policy.

* Use a better name and permission for the check in the default layout.
2017-10-27 18:01:11 -07:00
snipe
b1ac024725 Refined upload code 2017-10-27 17:40:10 -07:00
snipe
ec68bd7842 Small refactoring for code quality 2017-10-27 17:38:11 -07:00
snipe
a224904ade Removed uncessary code
This is already handled in the env
2017-10-27 17:00:33 -07:00
snipe
cb3b294baa Clesned up status label model for code quality 2017-10-26 22:54:07 -07:00
snipe
0788347990 Cleaned up status label method 2017-10-26 22:49:57 -07:00
snipe
7496a902bd Removed unused getDataView controller method
This is all API based now
2017-10-26 22:39:41 -07:00
snipe
f2d04be8fe Remove unused methods in Settings API controller (for now) 2017-10-26 22:35:01 -07:00
snipe
f2499fc7d2 Removed else condition on custom fields API for code quality 2017-10-26 22:33:40 -07:00
snipe
00d910ddbc Added manufacturers and categories select lists 2017-10-26 22:09:08 -07:00
snipe
c6d191bcba Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-26 21:52:04 -07:00
snipe
f13836eb55 Use select2 partials 2017-10-26 21:52:00 -07:00
snipe
76c4c19b3e Fixed small issues with select2 partials 2017-10-26 21:51:53 -07:00
snipe
1d212b59bd Added model select2 partial 2017-10-26 21:51:27 -07:00
snipe
1174d37c20 Added model selectlist route 2017-10-26 21:51:09 -07:00
snipe
6bcb55a129 Slight tweak to model name presenter 2017-10-26 21:50:39 -07:00
snipe
a99e09e5e3 Removed extra with() calls, since we load those up via the select2 lists now 2017-10-26 21:50:27 -07:00
snipe
7d11cb0748 Added selectlist transformer for select2 API calls 2017-10-26 21:50:01 -07:00
snipe
9c29ee9c6d Fixed datepicker in asset checkout 2017-10-26 19:51:29 -07:00
snipe
bdb95e4e3d Added companies ajax select2 endpoint 2017-10-26 16:37:41 -07:00
snipe
1fa6228fb7 Add @techincolor as a contributor 2017-10-26 16:32:32 -07:00
Danielle
8b535c1806 Default DB_HOST 127.0.0.1 instead of localhost (#4324) 2017-10-26 16:30:48 -07:00
snipe
b71d0ab484 Fixed order number and warranty bug in importer 2017-10-26 16:13:35 -07:00
snipe
ea07517ad5 Added more ajax select2 boxes to checkouts, remove helper ->with() methods 2017-10-26 03:43:28 -07:00
snipe
82690e1fd7 Integrate ajax select2 menus in all asset checkouts 2017-10-26 02:28:17 -07:00
snipe
75b527ab59 Features/image uploads (#4320)
* Locations API support for image

* Added manufacturers API support for image

* Added manufacturers API support for image

* Added image support for locations add/update

* Added manufacturer image upload support to controller

* General image string

* Added blade support for image uploads/delete image

* Added $request support (from Input::)

* Added image support in API transformers

* Added image to Manufacturers presenter for data table

* Migration to create image fields

* Ignore the contents of the new image directories

* Create new image upload directories

* Created components/consumables uploads directory

* Fixed missing textSearch scope from companies

* Added ignore for companies uploads directory

* Added blade support for image upload

* Fixed path to upload directory on edit

* Added company image upport to transformers, controllers

* Added image support for categories

* Added support for images in Departments

* Added support for image in Consumables

* Added image support for components
2017-10-25 22:35:58 -07:00
snipe
b083541723 Fixed docblock copypasta 2017-10-25 20:23:59 -07:00
snipe
6dbb598616 Merge branch 'develop' 2017-10-25 20:18:24 -07:00
snipe
e8d938e188 Bumped hash 2017-10-25 20:18:06 -07:00
snipe
f7c92f61e1 Merge branch 'develop' 2017-10-25 20:16:16 -07:00
snipe
4f80eac467 Prod assets 2017-10-25 20:15:34 -07:00
snipe
0e5af78cf1 New route for menu state saving 2017-10-25 20:15:30 -07:00
snipe
0d34cc704a Added controller for state-saver for sidenav 2017-10-25 20:10:59 -07:00
snipe
d4bb4d2edd Added state-save for open/cloed sidenav 2017-10-25 20:10:41 -07:00
snipe
d008334f2d Fixed #2857 - better CSS for requestable assets page when no results 2017-10-25 20:07:10 -07:00
snipe
109ea82cb9 Merge branch 'develop' 2017-10-25 18:17:38 -07:00
snipe
e8847753f4 Fixed importer using previous row’s custom field 2017-10-25 18:16:28 -07:00
snipe
7dad71d2b6 Fixed smaller button for import/cancel 2017-10-25 18:14:22 -07:00
snipe
db5968f95a Fixed larger button size 2017-10-25 18:13:55 -07:00
snipe
d97a1edeb4 Moved style sheet call back into page content 2017-10-25 18:13:41 -07:00
snipe
3dd39a46be Fixed large font size on importer 2017-10-25 18:13:21 -07:00
snipe
dc9a908de7 Fixing laravel mix() fuckery, hopefully for the last time 2017-10-25 18:13:03 -07:00
snipe
687cf44d3d Use inline style for logo 2017-10-25 16:15:50 -07:00
snipe
e054504669 lol whoops 2017-10-25 16:08:29 -07:00
snipe
e1ad28aa20 Mix fuckery 2017-10-25 16:05:39 -07:00
snipe
87992b7f71 More mix() fuckery 2017-10-25 16:05:18 -07:00
snipe
32478f1a10 Fixed #4310 - logo not scaling correctly without text 2017-10-25 15:47:06 -07:00
snipe
abc722b9c0 Fix path to overrides 2017-10-25 15:43:57 -07:00
snipe
49ebf4a314 Removed old build dir 2017-10-25 15:04:37 -07:00
snipe
c503729a9a Removed build vue 2017-10-25 15:03:04 -07:00
snipe
0b7864b09c Fixed model number not saving in modal 2017-10-25 13:17:35 -07:00
snipe
ede16eec3c Fixed #4308 - checkin and delete from user page 2017-10-25 11:11:32 -07:00
snipe
21c1ca2336 Bumped hash 2017-10-24 19:26:21 -07:00
snipe
a305b1ea2d Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-24 19:24:39 -07:00
snipe
17d58d9cc5 Added snazzy rich user selection menu
TODO:
- Abstract this out so it can be used by other select2 menus
- Write a select2 transformer to standardize output
2017-10-24 19:24:35 -07:00
snipe
c605984db0 Added nicer table formatting for “assets checked out to this user” table 2017-10-24 19:21:53 -07:00
snipe
d678a0ebff Switched to using JS routes for better subdirectory support, removed debugging console logs 2017-10-24 19:20:00 -07:00
snipe
e0fe383815 Removed debug message in SaveUserRequest 2017-10-24 19:18:53 -07:00
snipe
7140efc561 Use the transformers, Luke 2017-10-24 19:18:20 -07:00
snipe
99be54fd96 Fixed success message on saving new user 2017-10-24 19:17:30 -07:00
snipe
35da7906cc Fix standardized exception formatter for correct payload 2017-10-24 17:57:49 -07:00
snipe
680ad676ca Remove debugging 2017-10-24 17:10:42 -07:00
snipe
4628c15813 Fixed typo in comments 2017-10-24 16:57:04 -07:00
snipe
8a9960f830 Fixed missing break that would override password requirement 2017-10-24 16:56:46 -07:00
snipe
2b45433255 Removed copypasta commented out seeder code 2017-10-24 16:55:59 -07:00
snipe
715da63581 Check that model name exists before trying to display it
I don’t know why this would ever trigger, but a user in Gitter complained earlier today, so… ¯\_(ツ)_/¯
2017-10-24 16:53:46 -07:00
Brady Wetherington
ad32bae62f Fix to bad relation definition in Location. (#4306) 2017-10-24 16:52:45 -07:00
snipe
bbda0dc3b4 Always return an avatar, and set a fun default 2017-10-24 13:02:30 -07:00
snipe
dc805dd9b1 Added user avatars to listing 2017-10-24 09:51:07 -07:00
snipe
167cd4e4a0 Merge branch 'develop' 2017-10-24 05:25:52 -07:00
snipe
8d68bb7a57 Sticky headers for bootstrap tables 2017-10-24 05:22:26 -07:00
snipe
7d64ab3158 Fixes #4294 - pass correct group ID for group user listings 2017-10-24 04:39:47 -07:00
snipe
a41d603e0f Merge branch 'develop' 2017-10-23 21:17:43 -07:00
snipe
c18220069d Bumped version 2017-10-23 21:17:23 -07:00
snipe
fbf516284c One more time… 2017-10-23 21:13:39 -07:00
snipe
3db25dca7a Downgrade doctrine for php5.6 2017-10-23 20:54:52 -07:00
snipe
47c7061af5 Merge branch 'develop' 2017-10-23 20:11:01 -07:00
snipe
3799ab87ed Fixed search query for default sorting 2017-10-23 20:10:37 -07:00
snipe
6232a1f941 Merge branch 'develop' 2017-10-23 19:51:29 -07:00
snipe
f5ce580593 Bumped version 2017-10-23 19:51:14 -07:00
snipe
3afa5f7cda Merge branch 'develop' 2017-10-23 19:50:09 -07:00
snipe
17b271918f Fix date picker for custom fields 2017-10-23 19:47:43 -07:00
snipe
3922569d7f Merge branch 'develop' 2017-10-23 19:14:13 -07:00
Nicolai Essig
3a302fe2d7 ref #2737 prevent assets with "rtd_location_id" null values to be removed on location sort (#4283) 2017-10-23 18:28:06 -07:00
snipe
249f86bb21 Merge branch 'develop' 2017-10-23 17:50:58 -07:00
snipe
0951a756cc Updated passport to 3.0
Re: https://stackoverflow.com/a/45029309/200021
via @robertpearce
2017-10-23 17:35:31 -07:00
snipe
fc644925ea Fixes #4291 - adds phone to user listing 2017-10-23 14:21:51 -07:00
snipe
59c0b63ad0 Merge branch 'develop' 2017-10-20 20:22:42 -07:00
snipe
c0f8b3773c Temp fix for markdown stuff 2017-10-20 20:22:14 -07:00
snipe
fd210c6439 Fixes #4267 - email notifications showing model name as number 2017-10-20 18:58:11 -07:00
snipe
f7e23cf7c8 Fixes #4272 - adds serial to assigned assets view 2017-10-20 18:51:14 -07:00
snipe
387351d7ed Merge branch 'master' of github.com:snipe/snipe-it 2017-10-20 17:44:35 -07:00
snipe
6438d30afc Merge branch 'develop' 2017-10-20 17:44:28 -07:00
snipe
b4e1d37b16 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-20 17:44:04 -07:00
Brady Wetherington
8ac57d0121 Need to prefix status_id with assets. for uniqueness (#4279) 2017-10-20 17:37:46 -07:00
Kasey
d3b51715dc adding --force to php artistan snipeit:legacy-recrypt (#4232) 2017-10-20 17:21:21 -07:00
snipe
b215924b1a Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-20 17:18:13 -07:00
Brady Wetherington
25d3d66880 Add performance-improving indexes (#4278) 2017-10-20 17:17:11 -07:00
Brady Wetherington
189574377a Add 'where' clause to hasManyThrough relationship. (#4276) 2017-10-20 16:58:39 -07:00
snipe
341ddec9d8 Adds built-in mail notification vendor templates 2017-10-20 16:52:12 -07:00
Nicolai Essig
abcce78944 use translation for "All" in sidebar menu (#4268) 2017-10-20 00:20:33 -07:00
snipe
22e13cd4d2 Allow sorting on asset counts, disable delete button if the user has items checked out to them 2017-10-19 17:15:21 -07:00
snipe
5c105b52b6 Merge branch 'develop' 2017-10-19 16:45:22 -07:00
snipe
f757da1a98 Bumped hash 2017-10-19 16:45:04 -07:00
snipe
c1f8db37d9 Added note about saving before testing LDAP 2017-10-19 16:35:59 -07:00
snipe
cfc215a013 Merge branch 'develop' 2017-10-19 16:28:26 -07:00
snipe
4215a3257b Fixes #1044 - adds suppliers and image to accessories (#4266)
* Ignore accesories uploads

* API: Allow searching accessories by supplier id

* Adds suppliers and image upload to accessories

* Allow sorting by counts for suppliers

* Validate supplier image uploads

* Remove purchase_date from protected accessory array, it was converting it to datetime in datepicker
2017-10-19 16:25:24 -07:00
snipe
1f247ff541 Don’t let the user checkout an asset to itself
(We should consolidate that AssetCheckoutRequest for the API)
2017-10-19 15:51:55 -07:00
snipe
2fc46746e2 Adds translation string placeholders for new LDAP functionality 2017-10-19 12:22:54 -07:00
snipe
e185dc68af Fixes #4240 - allows admins to use custom password reset URL 2017-10-19 12:22:27 -07:00
snipe
54000ff69f Allows sorting by number of assets, etc in category 2017-10-19 11:48:09 -07:00
snipe
f6a38e848a Allows sorting by whether or not the category requires acceptance 2017-10-19 11:44:42 -07:00
snipe
7e8d670f81 Disable delete buttons if there are assets, etc 2017-10-19 11:41:35 -07:00
snipe
287b150b7f Show disabled delete button if thing can’t be deleted 2017-10-19 11:29:58 -07:00
snipe
b379656d55 Adds more consistent visual display of status label types 2017-10-19 11:06:55 -07:00
snipe
2e11a983c8 Nicer card display of status type explanations 2017-10-19 10:52:30 -07:00
snipe
a9753eb646 Include asset count in status labels overview 2017-10-19 10:48:15 -07:00
snipe
707c4db881 API: Check there are no assets associated before allowing delete 2017-10-19 10:39:08 -07:00
snipe
d1de34394e Removed stupid count method 2017-10-19 10:37:30 -07:00
snipe
e5719441bc Merge branch 'develop' 2017-10-19 08:36:05 -07:00
snipe
7153013fb0 Fake sending the test email if the app is in demo mode 2017-10-19 08:33:46 -07:00
snipe
55500f77fb Merge branch 'develop' 2017-10-19 08:20:44 -07:00
snipe
2b826c3adc Merge branch 'features/mail_test_button' into develop 2017-10-19 08:19:24 -07:00
snipe
cd193ce8bb Fixes #4036 - adds test email button to general settings 2017-10-19 08:18:56 -07:00
snipe
cb50142ba3 Update @thakilla as a contributor 2017-10-19 06:16:03 -07:00
snipe
81aaed92ce Change default session name 2017-10-19 06:08:58 -07:00
Nicolai Essig
4bc551db82 ref #4042 scale barcode with label size (#4258) 2017-10-19 06:08:01 -07:00
snipe
471d665408 Add @thakilla as a contributor 2017-10-19 06:07:42 -07:00
Robin Temme
068308ef56 Change changepassword menu icon to fixed width (#4262) 2017-10-19 06:04:02 -07:00
Nicolai Essig
1e65c7bf9a load custom css also on login page (#4260) 2017-10-19 06:01:41 -07:00
snipe
ae567c08db Fixes incorrect language reference for consumables on checkout if consumable doesn’t exist 2017-10-19 03:44:01 -07:00
snipe
0d25a4868a Merge branch 'develop' 2017-10-19 03:37:52 -07:00
snipe
13586be6b0 Fixed load error if license is invalid 2017-10-19 03:37:27 -07:00
snipe
44c649c3c8 Fixes #4256 - double encoding on user bulk checkin and delete blade 2017-10-19 03:17:55 -07:00
snipe
1a7bfb75fa Merge branch 'develop' 2017-10-19 02:22:39 -07:00
snipe
2b803a6a6c Fixes #4257 - use admin url when editing groups 2017-10-19 02:22:05 -07:00
snipe
92e4bdc02e Merge branch 'develop' 2017-10-19 02:09:06 -07:00
snipe
4d3d19ca2b Fixes older route reference in consumables 2017-10-19 02:07:31 -07:00
snipe
9c06912efd Small tweaks to prevent Chrome autofill 2017-10-19 01:59:13 -07:00
snipe
c5893b4445 Fixes #4249 - display deployed location in listing 2017-10-19 01:30:40 -07:00
snipe
b90933bb8b Fixes #4139 - fixed route for deleting file 2017-10-19 01:11:24 -07:00
snipe
fe9a90854d Adds d.m.Y as date format, per #2423 2017-10-18 10:30:25 -07:00
snipe
3b012f2827 Some advanced search query tweaks 2017-10-18 10:07:35 -07:00
snipe
e31dadc99a Merge branch 'develop' 2017-10-18 09:28:00 -07:00
snipe
5519e2d4ae Fixes custom fields sorting on asset listings
I need a silkwood shower :(
2017-10-18 09:27:34 -07:00
snipe
6285a8b5b2 Merge branch 'develop' 2017-10-18 08:54:35 -07:00
snipe
a3139c6fc6 Fix accessories route for invalid accessory ID 2017-10-18 08:53:25 -07:00
snipe
389ba9059f Merge branch 'develop' 2017-10-18 08:45:22 -07:00
snipe
c0e50be03e Duh. Helps if you actually assign the array first. 2017-10-18 08:45:05 -07:00
snipe
447833c996 Only try to process model bulk editing if at least one model was selected 2017-10-18 08:15:54 -07:00
snipe
809e310565 Recrypt the LDAP password properly
Older installs should add a line to their .env:

`LEGACY_CIPHER=rijndael-256`
2017-10-18 08:15:23 -07:00
snipe
38dd03b5ad Merge branch 'develop' 2017-10-18 07:16:19 -07:00
snipe
68f6385eba Fixes 500 in bulk checkout if no asset is selected 2017-10-18 07:15:16 -07:00
snipe
bd376a4992 Possible fix for #4227 2017-10-18 07:02:18 -07:00
snipe
97f65ceac0 Merge branch 'develop' 2017-10-18 06:25:01 -07:00
snipe
9e39abcc32 Merge branch 'develop' of github.com:snipe/snipe-it into develop 2017-10-18 06:24:41 -07:00
snipe
5cd2857d5d Use footer sumformatter for cost totals 2017-10-18 06:24:36 -07:00
snipe
585fcfb7d4 Use maintenances report API to populate the maintenances report 2017-10-18 05:47:47 -07:00
snipe
d9135a8aac Disallow deleting suppliers with associated assets, licenses or maintenances 2017-10-18 05:47:20 -07:00
snipe
081a64223a Add @TonisOrmisson as a contributor 2017-10-18 05:45:14 -07:00
Tõnis Ormisson
a4eeff01f0 FIXED upgrade Recrypt not working with changed cipher (#4245)
* FIX legacy cipher change

* FIX Recrypt Custom fields column names

* FIX ReCrypt Clean un-needed code
2017-10-18 05:43:54 -07:00
snipe
eedbe468ac Fix licenses not saving supplier id on edit 2017-10-18 05:43:15 -07:00
snipe
463d9513e2 Merge branch 'develop' 2017-10-18 04:49:16 -07:00
snipe
ed4aa7dec2 Account for deleted suppliers in asset maintenances report
This should all be reworked via the API though anyway
2017-10-18 04:48:52 -07:00
snipe
d6bbe15a76 Added upload state back to log test 2017-10-18 04:04:05 -07:00
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
1811 changed files with 30347 additions and 34164 deletions

View File

@@ -755,6 +755,60 @@
"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"
]
},
{
"login": "TonisOrmisson",
"name": "Tõnis Ormisson",
"avatar_url": "https://avatars1.githubusercontent.com/u/6357451?v=4",
"profile": "http://andmemasin.eu",
"contributions": [
"code"
]
},
{
"login": "thakilla",
"name": "Nicolai Essig",
"avatar_url": "https://avatars0.githubusercontent.com/u/449411?v=4",
"profile": "http://www.nicolai-essig.de",
"contributions": [
"code"
]
},
{
"login": "techincolor",
"name": "Danielle",
"avatar_url": "https://avatars1.githubusercontent.com/u/14809698?v=4",
"profile": "https://github.com/techincolor",
"contributions": [
"doc"
]
}
]
}

View File

@@ -8,12 +8,11 @@ APP_URL=null
APP_TIMEZONE='UTC'
APP_LOCALE=en
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=localhost
DB_HOST=127.0.0.1
DB_DATABASE=null
DB_USERNAME=null
DB_PASSWORD=null
@@ -31,7 +30,6 @@ DB_SSL_CERT_PATH=null
DB_SSL_CA_PATH=null
DB_SSL_CIPHER=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
@@ -46,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
# --------------------------------------------
@@ -64,14 +60,12 @@ COOKIE_NAME=snipeit_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: SECURITY HEADER SETTINGS
# --------------------------------------------
REFERRER_POLICY=strict-origin
REFERRER_POLICY=same-origin
ENABLE_CSP=false
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
@@ -79,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
@@ -97,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

8
.gitignore vendored
View File

@@ -27,8 +27,16 @@ public/uploads/logo.png
public/uploads/logo.svg
public/uploads/models/*
public/uploads/suppliers/*
public/uploads/accessories/*
public/uploads/locations/*
public/uploads/manufacturers/*
public/uploads/components/*
public/uploads/consumables/*
public/uploads/companies/*
public/uploads/categories/*
public/uploads/users/*
storage/app/private_uploads/users/*
public/uploads/departments/*
storage/debugbar/
storage/dumps/*
storage/laravel-backups

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.

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.

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-81-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-87-orange.svg?style=flat-square)](#contributors)
## Snipe-IT - Open Source Asset Management System
@@ -67,7 +67,8 @@ 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://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://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [<img src="https://avatars1.githubusercontent.com/u/6551003?v=4" width="110px;"/><br /><sub>Richard Hofman</sub>](https://github.com/richardhofman6)<br />[💻](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [<img src="https://avatars0.githubusercontent.com/u/3697569?v=4" width="110px;"/><br /><sub>gizzmojr</sub>](https://github.com/gizzmojr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [<img src="https://avatars3.githubusercontent.com/u/404729?v=4" width="110px;"/><br /><sub>Jenny Li</sub>](https://github.com/imjennyli)<br />[📖](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/869227?v=4" width="110px;"/><br /><sub>Geoff Young</sub>](https://github.com/GeoffYoung)<br />[💻](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [<img src="https://avatars3.githubusercontent.com/u/1068477?v=4" width="110px;"/><br /><sub>Elliot Blackburn</sub>](http://www.elliotblackburn.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

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;
}
}
}

View File

@@ -16,7 +16,8 @@ class RecryptFromMcrypt extends Command
*
* @var string
*/
protected $signature = 'snipeit:legacy-recrypt';
protected $signature = 'snipeit:legacy-recrypt
{--force : Force a re-crypt of encrypted data from MCRYPT.}';
/**
* The console command description.
@@ -48,6 +49,7 @@ class RecryptFromMcrypt extends Command
// 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);
$legacy_cipher = env('LEGACY_CIPHER');
$errors = array();
if (!$legacy_key) {
@@ -60,6 +62,7 @@ class RecryptFromMcrypt extends Command
if (strlen($legacy_key) == 32) {
$legacy_length_check = true;
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1])==44)) {
$legacy_key = base64_decode($key_parts[1],true);
$legacy_length_check = true;
} else {
$legacy_length_check = false;
@@ -79,7 +82,9 @@ class RecryptFromMcrypt extends Command
$this->error('================================!!!! WARNING !!!!================================');
$this->comment("This tool will attempt to decrypt your old Snipe-IT (mcrypt, now deprecated) encrypted data and re-encrypt it using OpenSSL. \n\nYou should only continue if you have backed up any and all old APP_KEYs and have backed up your data.");
if ($this->confirm("Are you SURE you wish to continue?")) {
$force = ($this->option('force')) ? true : false;
if ($force || ($this->confirm("Are you SURE you wish to continue?"))) {
$backup_file = 'backups/env-backups/'.'app_key-'.date('Y-m-d-gis');
@@ -91,13 +96,21 @@ class RecryptFromMcrypt extends Command
}
$mcrypter = new McryptEncrypter($legacy_key);
if ($legacy_cipher){
$mcrypter = new McryptEncrypter($legacy_key,$legacy_cipher);
}else{
$mcrypter = new McryptEncrypter($legacy_key);
}
$settings = Setting::getSettings();
if ($settings->ldap_password=='') {
if ($settings->ldap_pword=='') {
$this->comment('INFO: No LDAP password found. Skipping... ');
} else {
$decrypted_ldap_pword = $mcrypter->decrypt($settings->ldap_pword);
$settings->ldap_pword = \Crypt::encrypt($decrypted_ldap_pword);
$settings->save();
}
/** @var CustomField[] $custom_fields */
$custom_fields = CustomField::where('field_encrypted','=', 1)->get();
$this->comment('INFO: Retrieving encrypted custom fields...');
@@ -110,32 +123,22 @@ class RecryptFromMcrypt extends Command
// Get all assets with a value in any of the fields that were encrypted
/** @var Asset[] $assets */
$assets = $query->get();
$bar = $this->output->createProgressBar(count($assets));
foreach ($custom_fields as $encrypted_field) {
// Try to decrypt the payload using the legacy app key
try {
$decrypted_field = $mcrypter->decrypt($encrypted_field);
$this->comment($decrypted_field);
} catch (\Exception $e) {
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
}
$bar->advance();
}
foreach ($assets as $asset) {
foreach ($custom_fields as $encrypted_field) {
$columnName = $encrypted_field->db_column;
// Make sure the value isn't null
if ($asset->{$encrypted_field}!='') {
if ($asset->{$columnName}!='') {
// Try to decrypt the payload using the legacy app key
try {
$decrypted_field = $mcrypter->decrypt($asset->{$encrypted_field});
$asset->{$encrypted_field} = \Crypt::encrypt($decrypted_field);
$decrypted_field = $mcrypter->decrypt($asset->{$columnName});
$asset->{$columnName} = \Crypt::encrypt($decrypted_field);
$this->comment($decrypted_field);
} catch (\Exception $e) {
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();

View File

@@ -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();
}
}
}

View File

@@ -25,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
];
/**
@@ -39,7 +40,7 @@ class Kernel extends ConsoleKernel
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:expected-checkins')->daily();
$schedule->command('snipeit:expected-checkin')->daily();
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
}

View File

@@ -7,6 +7,6 @@ class CheckoutNotAllowed extends Exception
{
public function __toString()
{
"A checkout is not allowed under these circumstances";
return "A checkout is not allowed under these circumstances";
}
}

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);
}
}
/**
@@ -63,7 +67,7 @@ class Handler extends ExceptionHandler
}
if ($e instanceof \Illuminate\Validation\ValidationException) {
return response()->json(Helper::formatStandardApiResponse('error', $e->response['messages'], $e->getMessage(), 400));
return response()->json(Helper::formatStandardApiResponse('error', null, $e->response['messages'], 400));
}
if ($this->isHttpException($e)) {

View File

@@ -18,6 +18,8 @@ use Illuminate\Http\Request;
use Slack;
use Str;
use View;
use Image;
use App\Http\Requests\ImageUploadRequest;
/** This controller handles all actions related to Accessories for
* the Snipe-IT Asset Management application.
@@ -52,13 +54,9 @@ class AccessoriesController extends Controller
public function create(Request $request)
{
$this->authorize('create', Accessory::class);
// Show the page
return view('accessories/edit')
->with('item', new Accessory)
->with('category_list', Helper::categoryList('accessory'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList())
->with('manufacturer_list', Helper::manufacturerList());
$category_type = 'accessory';
return view('accessories/edit')->with('category_type', $category_type)
->with('item', new Accessory);
}
@@ -68,7 +66,7 @@ class AccessoriesController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @return Redirect
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize(Accessory::class);
// create a new model instance
@@ -87,6 +85,28 @@ class AccessoriesController extends Controller
$accessory->purchase_cost = Helper::ParseFloat(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->user_id = Auth::user()->id;
$accessory->supplier_id = request('supplier_id');
if ($request->hasFile('image')) {
if (!config('app.lock_passwords')) {
$image = $request->file('image');
$ext = $image->getClientOriginalExtension();
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 250, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
$accessory->image = $file_name;
}
}
// Was the accessory created?
if ($accessory->save()) {
@@ -105,18 +125,15 @@ class AccessoriesController extends Controller
*/
public function edit(Request $request, $accessoryId = null)
{
// Check if the accessory exists
if (is_null($item = Accessory::find($accessoryId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
if ($item = Accessory::find($accessoryId)) {
$this->authorize($item);
$category_type = 'accessory';
return view('accessories/edit', compact('item'))->with('category_type', $category_type);
}
$this->authorize($item);
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
return view('accessories/edit', compact('item'))
->with('category_list', Helper::categoryList('accessory'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList())
->with('manufacturer_list', Helper::manufacturerList());
}
@@ -127,7 +144,7 @@ class AccessoriesController extends Controller
* @param int $accessoryId
* @return Redirect
*/
public function update(Request $request, $accessoryId = null)
public function update(ImageUploadRequest $request, $accessoryId = null)
{
if (is_null($accessory = Accessory::find($accessoryId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
@@ -144,11 +161,38 @@ class AccessoriesController extends Controller
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = request('purchase_cost');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = request('purchase_cost');
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
// Was the accessory updated?
if ($request->hasFile('image')) {
if (!config('app.lock_passwords')) {
$image = $request->file('image');
$ext = $image->getClientOriginalExtension();
$file_name = "accessory-".str_random(18).'.'.$ext;
$path = public_path('/uploads/accessories');
if ($image->getClientOriginalExtension()!='svg') {
Image::make($image->getRealPath())->resize(null, 250, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path.'/'.$file_name);
} else {
$image->move($path, $file_name);
}
if (($accessory->image) && (file_exists($path.'/'.$accessory->image))) {
unlink($path.'/'.$accessory->image);
}
$accessory->image = $file_name;
}
}
// Was the accessory updated?
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
@@ -197,11 +241,7 @@ class AccessoriesController extends Controller
if (isset($accessory->id)) {
return view('accessories/view', compact('accessory'));
}
// Prepare the error message
$error = trans('admin/accessories/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('accessories')->with('error', $error);
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist', compact('id')));
}
/**
@@ -222,7 +262,7 @@ class AccessoriesController extends Controller
$this->authorize('checkout', $accessory);
// Get the dropdown of users and then pass it to the checkout view
return view('accessories/checkout', compact('accessory'))->with('users_list', Helper::usersList());
return view('accessories/checkout', compact('accessory'));
}
@@ -247,7 +287,7 @@ class AccessoriesController extends Controller
$this->authorize('checkout', $accessory);
if (!$user = User::find(Input::get('assigned_to'))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
return redirect()->route('checkout/accessory', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
}
// Update the accessory data
@@ -274,6 +314,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())) && ($user->email!='')) {
Mail::send('emails.accept-accessory', $data, function ($m) use ($user) {
@@ -369,143 +410,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;
}
}

View File

@@ -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
@@ -37,6 +38,10 @@ class AccessoriesController extends Controller
$accessories->where('manufacturer_id','=',$request->input('manufacturer_id'));
}
if ($request->has('supplier_id')) {
$accessories->where('supplier_id','=',$request->input('supplier_id'));
}
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -95,8 +100,6 @@ class AccessoriesController extends Controller
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::findOrFail($id);
$accessory_users = $accessory->users;
return (new AccessoriesTransformer)->transformAccessory($accessory);
}
@@ -128,9 +131,15 @@ class AccessoriesController extends Controller
public function checkedout($id)
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::findOrFail($id)->with('users')->first();
$total = $accessory->users->count();
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $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);
}

View File

@@ -8,6 +8,7 @@ use App\Helpers\Helper;
use Illuminate\Http\Request;
use App\Http\Transformers\AssetModelsTransformer;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\SelectlistTransformer;
/**
@@ -31,7 +32,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 +40,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);
@@ -154,8 +159,51 @@ class AssetModelsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.assoc_users')));
}
if ($assetmodel->image) {
try {
unlink(public_path().'/uploads/models/'.$assetmodel->image);
} catch (\Exception $e) {
\Log::error($e);
}
}
$assetmodel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/assetmodels/message.delete.success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', AssetModel::class);
$assetmodels = AssetModel::select([
'models.id',
'models.name',
'models.image',
'models.model_number',
]);
if ($request->has('search')) {
$assetmodels = $assetmodels->where('models.name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('models.model_number', 'LIKE', '%'.$request->get('search').'%');
}
$assetmodels = $assetmodels->paginate(50);
foreach ($assetmodels as $assetmodel) {
$assetmodel->use_text = $assetmodel->present()->modelName;
$assetmodel->use_image = ($assetmodel->image) ? url('/').'/uploads/models/'.$assetmodel->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($assetmodels);
}
}

View File

@@ -30,6 +30,7 @@ use Str;
use TCPDF;
use Validator;
use View;
use App\Http\Transformers\SelectlistTransformer;
/**
@@ -69,7 +70,8 @@ class AssetsController extends Controller
'created_at',
'updated_at',
'purchase_date',
'purchase_cost'
'purchase_cost',
'warranty_months',
];
$filter = array();
@@ -84,21 +86,21 @@ class AssetsController extends Controller
}
$assets = Company::scopeCompanyables(Asset::select('assets.*'))->with(
'assetloc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
'location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
// If we should search on everything
if (($request->has('search')) && (count($filter) == 0)) {
if (count($filter) > 0) {
$assets->ByFilter($filter);
} elseif ($request->has('search')) {
$assets->TextSearch($request->input('search'));
// otherwise loop through the filters and search strictly on them
} else {
if (count($filter) > 0) {
$assets->ByFilter($filter);
}
}
// 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'));
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
if ($request->has('model_id')) {
@@ -125,7 +127,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);
@@ -133,36 +139,76 @@ 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);
});
}
// This is kinda gross, but we need to do this because the Bootstrap Tables
// API passes custom field ordering as custom_fields.fieldname, and we have to strip
// that out to let the default sorter below order them correctly on the assets table.
$sort_override = str_replace('custom_fields.','', $request->input('sort')) ;
// This handles all of the pivot sorting (versus the assets.* fields in the allowed_columns array)
$column_sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets.created_at';
switch ($request->input('sort')) {
// This handles all of the pivot sorting (versus the assets.* fields
// in the allowed_columns array)
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.created_at';
switch ($sort_override) {
case 'model':
$assets->OrderModels($order);
break;
@@ -211,12 +257,54 @@ class AssetsController extends Controller
*/
public function show($id)
{
if ($asset = Asset::withTrashed()->find($id)) {
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->findOrFail($id)) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Asset::class);
$assets = Company::scopeCompanyables(Asset::select([
'assets.id',
'assets.name',
'assets.asset_tag',
'assets.model_id',
]))->with('model')->RTD();
if ($request->has('search')) {
$assets = $assets->where('assets.name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('assets.asset_tag', 'LIKE', '%'.$request->get('search').'%')
->join('models AS assets_models',function ($join) use ($request) {
$join->on('assets_models.id', "=", "assets.model_id");
})->orWhere('assets_models.name','LIKE','%'.$request->get('search').'%');
}
$assets = $assets->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($assets as $asset) {
$asset->use_text = $asset->present()->fullName;
$asset->use_image = ($asset->getImageUrl()) ? $asset->getImageUrl() : null;
}
return (new SelectlistTransformer)->transformSelectlist($assets);
}
@@ -261,12 +349,12 @@ class AssetsController extends Controller
$model = AssetModel::find($request->get('model_id'));
if ($model->fieldset) {
foreach ($model->fieldset->fields as $field) {
$asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug()));
$asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug(), null));
}
}
if ($asset->save()) {
$asset->logCreate();
if ($request->get('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif ($request->get('assigned_asset')) {
@@ -413,23 +501,47 @@ class AssetsController extends Controller
$this->authorize('checkout', $asset);
$error_payload = [];
$error_payload['asset'] = [
'id' => $asset->id,
'asset_tag' => $asset->asset_tag,
];
if ($request->has('user_id')) {
$target = User::find($request->input('user_id'));
$error_payload['target_id'] = $request->input('user_id');
$error_payload['target_type'] = User::class;
// Don't let the user check an asset out to itself
} elseif ($request->has('asset_id')) {
$target = Asset::find($request->input('asset_id'));
$target = Asset::where('id','!=',$asset_id)->find($request->input('asset_id'));
$error_payload['target_id'] = $request->input('asset_id');
$error_payload['target_type'] = Asset::class;
} elseif ($request->has('location_id')) {
$target = Location::find($request->input('location_id'));
$error_payload['target_id'] = $request->input('location_id');
$error_payload['target_type'] = Location::class;
}
if (!isset($target)) {
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], 'No valid checkout target specified for asset '.e($asset->asset_tag).'.'));
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'No valid checkout target specified for asset '.e($asset->asset_tag).'.'));
}
$checkout_at = request('checkout_at', date("Y-m-d H:i:s"));
$expected_checkin = request('expected_checkin', null);
$note = request('note', null);
$asset_name = request('name', null);
// Set the location ID to the RTD location id if there is one
if ($asset->rtd_location_id!='') {
$asset->location_id = $target->rtd_location_id;
}
// Overwrite that if the target has a location ID though
if ($target->location_id!='') {
$asset->location_id = $target->location_id;
}
if ($asset->checkOut($target, Auth::user(), $checkout_at, $expected_checkin, $note, $asset_name)) {
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
@@ -481,6 +593,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) {

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Category;
use App\Http\Transformers\CategoriesTransformer;
use App\Http\Transformers\SelectlistTransformer;
class CategoriesController extends Controller
{
@@ -20,9 +21,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', 'assets_count', 'accessories_count', 'consumables_count', 'components_count', 'image'];
$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','image'])
->withCount('assets', 'accessories', 'consumables', 'components');
if ($request->has('search')) {
@@ -32,7 +33,7 @@ class CategoriesController extends Controller
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'assets_count';
$categories->orderBy($sort, $order);
$total = $categories->count();
@@ -128,4 +129,41 @@ class CategoriesController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request, $category_type = 'asset')
{
$this->authorize('view', Categories::class);
$categories = Category::select([
'id',
'name',
'image',
]);
if ($request->has('search')) {
$categories = $categories->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$categories = $categories->where('category_type', $category_type)->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($categories as $category) {
$category->use_image = ($category->image) ? url('/').'/uploads/categories/'.$category->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($categories);
}
}

View File

@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Company;
use App\Http\Transformers\SelectlistTransformer;
class CompaniesController extends Controller
{
@@ -141,4 +142,38 @@ class CompaniesController extends Controller
}
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Company::class);
$companies = Company::select([
'companies.id',
'companies.name',
'companies.image',
]);
if ($request->has('search')) {
$companies = $companies->where('companies.name', 'LIKE', '%'.$request->get('search').'%');
}
$companies = $companies->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($companies as $company) {
$company->use_image = ($company->image) ? url('/').'/uploads/companies/'.$company->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($companies);
}
}

View File

@@ -34,7 +34,7 @@ class ComponentsController extends Controller
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['id','name','min_amt','order_number','serial','purchase_date','purchase_cost','company','category','qty','location'];
$allowed_columns = ['id','name','min_amt','order_number','serial','purchase_date','purchase_cost','company','category','qty','location','image'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
@@ -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);
}
}

View File

@@ -43,7 +43,7 @@ class ConsumablesController extends Controller
$offset = request('offset', 0);
$limit = request('limit', 50);
$allowed_columns = ['id','name','order_number','min_amt','purchase_date','purchase_cost','company','category','model_number', 'item_no', 'manufacturer','location','qty'];
$allowed_columns = ['id','name','order_number','min_amt','purchase_date','purchase_cost','company','category','model_number', 'item_no', 'manufacturer','location','qty','image'];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';

View File

@@ -57,15 +57,15 @@ class CustomFieldsController extends Controller
*/
public function destroy($field_id)
{
$field = CustomField::find($field_id);
$field = CustomField::findOrFail($field_id);
if ($field->fieldset->count() >0) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Field is in use.'));
} else {
$field->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.field.delete.success')));
}
$field->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/custom_fields/message.field.delete.success')));
}
}

View File

@@ -8,6 +8,7 @@ use App\Models\Department;
use App\Http\Transformers\DepartmentsTransformer;
use App\Helpers\Helper;
use Auth;
use App\Http\Transformers\SelectlistTransformer;
class DepartmentsController extends Controller
{
@@ -21,7 +22,7 @@ class DepartmentsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Department::class);
$allowed_columns = ['id','name'];
$allowed_columns = ['id','name','image'];
$departments = Department::select([
'id',
@@ -30,7 +31,8 @@ class DepartmentsController extends Controller
'company_id',
'manager_id',
'created_at',
'updated_at'
'updated_at',
'image'
])->with('users')->with('location')->with('manager')->with('company')->withCount('users');
if ($request->has('search')) {
@@ -110,4 +112,39 @@ class DepartmentsController extends Controller
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Department::class);
$departments = Department::select([
'id',
'name',
'image',
]);
if ($request->has('search')) {
$departments = $departments->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$departments = $departments->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($departments as $department) {
$department->use_image = ($department->image) ? url('/').'/uploads/departments/'.$department->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($departments);
}
}

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Location;
use App\Http\Transformers\LocationsTransformer;
use App\Http\Transformers\SelectlistTransformer;
class LocationsController extends Controller
{
@@ -20,8 +21,10 @@ class LocationsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Location::class);
$allowed_columns = ['id','name','address','address2','city','state','country','zip','created_at',
'updated_at','parent_id', 'manager_id'];
$allowed_columns = [
'id','name','address','address2','city','state','country','zip','created_at',
'updated_at','parent_id', 'manager_id','image',
'rtd_assets_count','users_count','assets_count'];
$locations = Location::with('parent', 'manager', 'childLocations')->select([
'locations.id',
@@ -36,9 +39,9 @@ class LocationsController extends Controller
'locations.manager_id',
'locations.created_at',
'locations.updated_at',
'locations.image',
'locations.currency'
])->withCount('locationAssets')
->withCount('assignedAssets')
])->withCount('rtd_assets')
->withCount('assets')
->withCount('users');
@@ -138,4 +141,41 @@ class LocationsController extends Controller
$location->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Location::class);
$locations = Location::select([
'locations.id',
'locations.name',
'locations.image',
]);
if ($request->has('search')) {
$locations = $locations->where('locations.name', 'LIKE', '%'.$request->get('search').'%');
}
$locations = $locations->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($locations as $location) {
$location->use_text = $location->name;
$location->use_image = ($location->image) ? url('/').'/uploads/locations/'.$location->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($locations);
}
}

View File

@@ -8,6 +8,7 @@ use App\Helpers\Helper;
use App\Models\Manufacturer;
use App\Http\Transformers\DatatablesTransformer;
use App\Http\Transformers\ManufacturersTransformer;
use App\Http\Transformers\SelectlistTransformer;
class ManufacturersController extends Controller
{
@@ -21,10 +22,10 @@ class ManufacturersController extends Controller
public function index(Request $request)
{
$this->authorize('view', Manufacturer::class);
$allowed_columns = ['id','name','url','support_url','support_email','support_phone','created_at','updated_at'];
$allowed_columns = ['id','name','url','support_url','support_email','support_phone','created_at','updated_at','image'];
$manufacturers = Manufacturer::select(
array('id','name','url','support_url','support_email','support_phone','created_at','updated_at')
array('id','name','url','support_url','support_email','support_phone','created_at','updated_at','image')
)->withCount('assets')->withCount('licenses')->withCount('consumables')->withCount('accessories');
@@ -120,4 +121,40 @@ class ManufacturersController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Manufacturers::class);
$manufacturers = Manufacturer::select([
'id',
'name',
'image',
]);
if ($request->has('search')) {
$manufacturers = $manufacturers->where('name', 'LIKE', '%'.$request->get('search').'%');
}
$manufacturers = $manufacturers->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($manufacturers as $manufacturer) {
$manufacturer->use_text = $manufacturer->name;
$manufacturer->use_image = ($manufacturer->image) ? url('/').'/uploads/manufacturers/'.$manufacturer->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($manufacturers);
}
}

View File

@@ -5,78 +5,22 @@ namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Ldap;
use Validator;
use App\Models\Setting;
use Mail;
class SettingsController extends Controller
{
/**
* Display a listing of the resource.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*
* @return \Illuminate\Http\Response
*/
public function index()
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);
}
/**
* Store a newly created resource in storage.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
public function getLdapTest()
{
\Log::debug('Preparing to test LDAP connection');
try {
@@ -98,4 +42,85 @@ 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);
}
}
/**
* Test the email configuration
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function ajaxTestEmail()
{
if (!config('app.lock_passwords')) {
try {
Mail::send('emails.test', [], function ($m) {
$m->to(config('mail.from.address'), config('mail.from.name'));
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.test_email'));
});
return response()->json(['message' => 'Mail sent to '.config('mail.from.address')], 200);
} catch (Exception $e) {
return response()->json(['message' => $e->getMessage()], 500);
}
}
return response()->json(['message' => 'Mail would have been sent, but this application is in demo mode! '], 200);
}
}

View File

@@ -22,7 +22,7 @@ class StatuslabelsController extends Controller
public function index(Request $request)
{
$this->authorize('view', Statuslabel::class);
$allowed_columns = ['id','name','created_at'];
$allowed_columns = ['id','name','created_at', 'assets_count'];
$statuslabels = Statuslabel::withCount('assets');
@@ -137,8 +137,14 @@ class StatuslabelsController extends Controller
$this->authorize('delete', Statuslabel::class);
$statuslabel = Statuslabel::findOrFail($id);
$this->authorize('delete', $statuslabel);
$statuslabel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/statuslabels/message.delete.success')));
// Check that there are no assets associated
if ($statuslabel->assets()->count() == 0) {
$statuslabel->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/statuslabels/message.delete.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/statuslabels/message.assoc_assets')));
}
@@ -155,22 +161,23 @@ class StatuslabelsController extends Controller
public function getAssetCountByStatuslabel()
{
$statusLabels = Statuslabel::with('assets')->get();
$statuslabels = Statuslabel::with('assets')->groupBy('id')->withCount('assets')->get();
$labels=[];
$points=[];
$colors=[];
foreach ($statusLabels as $statusLabel) {
if ($statusLabel->assets()->count() > 0) {
$labels[]=$statusLabel->name;
$points[]=$statusLabel->assets()->whereNull('assigned_to')->count();
if ($statusLabel->color!='') {
$colors[]=$statusLabel->color;
foreach ($statuslabels as $statuslabel) {
if ($statuslabel->assets_count > 0) {
$labels[]=$statuslabel->name. ' ('.number_format($statuslabel->assets_count).')';
$points[]=$statuslabel->assets_count;
if ($statuslabel->color!='') {
$colors[]=$statuslabel->color;
}
}
}
$labels[]='Deployed';
$points[]=Asset::whereNotNull('assigned_to')->count();
$colors_array = array_merge($colors, Helper::chartColors());
$result= [

View File

@@ -7,6 +7,8 @@ use App\Http\Controllers\Controller;
use App\Helpers\Helper;
use App\Models\Supplier;
use App\Http\Transformers\SuppliersTransformer;
use App\Http\Transformers\SelectlistTransformer;
class SuppliersController extends Controller
{
@@ -20,11 +22,11 @@ class SuppliersController extends Controller
public function index(Request $request)
{
$this->authorize('view', Supplier::class);
$allowed_columns = ['id','name','address','phone','contact','fax','email'];
$allowed_columns = ['id','name','address','phone','contact','fax','email','image','assets_count','licenses_count', 'accessories_count'];
$suppliers = Supplier::select(
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at')
)->withCount('assets')->withCount('licenses')->whereNull('deleted_at');
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image')
)->withCount('assets')->withCount('licenses')->withCount('accessories')->whereNull('deleted_at');
if ($request->has('search')) {
@@ -113,10 +115,61 @@ class SuppliersController extends Controller
public function destroy($id)
{
$this->authorize('delete', Supplier::class);
$supplier = Supplier::findOrFail($id);
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances','assets', 'licenses')->findOrFail($id);
$this->authorize('delete', $supplier);
if ($supplier->assets_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count])));
}
if ($supplier->asset_maintenances_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count])));
}
if ($supplier->licenses_count > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_licenses', ['licenses_count' => (int) $supplier->licenses_count])));
}
$supplier->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success')));
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', Supplier::class);
$suppliers = Supplier::select([
'id',
'name',
'image',
]);
if ($request->has('search')) {
$suppliers = $suppliers->where('suppliers.name', 'LIKE', '%'.$request->get('search').'%');
}
$suppliers = $suppliers->orderBy('name', 'ASC')->paginate(50);
// Loop through and set some custom properties for the transformer to use.
// This lets us have more flexibility in special cases like assets, where
// they may not have a ->name value but we want to display something anyway
foreach ($suppliers as $supplier) {
$supplier->use_text = $supplier->name;
$supplier->use_image = ($supplier->image) ? url('/').'/uploads/suppliers/'.$supplier->image : null;
}
return (new SelectlistTransformer)->transformSelectlist($suppliers);
}
}

View File

@@ -10,6 +10,8 @@ use App\Models\User;
use App\Helpers\Helper;
use App\Http\Requests\SaveUserRequest;
use App\Models\Asset;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\SelectlistTransformer;
class UsersController extends Controller
{
@@ -31,6 +33,12 @@ class UsersController extends Controller
'users.two_factor_enrolled',
'users.jobtitle',
'users.email',
'users.phone',
'users.address',
'users.city',
'users.state',
'users.country',
'users.zip',
'users.username',
'users.location_id',
'users.manager_id',
@@ -42,8 +50,10 @@ class UsersController extends Controller
'users.last_login',
'users.deleted_at',
'users.department_id',
'users.activated'
])->with('manager', 'groups', 'userloc', 'company', 'department','throttle','assets','licenses','accessories','consumables')
'users.activated',
'users.avatar',
])->with('manager', 'groups', 'location', 'company', 'department','throttle','assets','licenses','accessories','consumables')
->withCount('assets','licenses','accessories','consumables');
$users = Company::scopeCompanyables($users);
@@ -57,7 +67,6 @@ class UsersController extends Controller
$users = $users->GetDeleted();
}
if ($request->has('company_id')) {
$users = $users->where('company_id', '=', $request->input('company_id'));
}
@@ -65,6 +74,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->get('group_id'));
}
if ($request->has('department_id')) {
$users = $users->where('department_id','=',$request->input('department_id'));
@@ -89,7 +102,9 @@ class UsersController extends Controller
[
'last_name','first_name','email','jobtitle','username','employee_num',
'assets','accessories', 'consumables','licenses','groups','activated','created_at',
'two_factor_enrolled','two_factor_optin','last_login'
'two_factor_enrolled','two_factor_optin','last_login', 'assets_count', 'licenses_count',
'consumables_count', 'accessories_count', 'phone', 'address', 'city', 'state',
'country', 'zip'
];
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
@@ -102,6 +117,63 @@ class UsersController extends Controller
}
/**
* Gets a paginated collection for the select2 menus
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @see \App\Http\Transformers\SelectlistTransformer
*
*/
public function selectlist(Request $request)
{
$this->authorize('view', User::class);
$users = User::select(
[
'users.id',
'users.employee_num',
'users.first_name',
'users.last_name',
'users.gravatar',
'users.avatar',
'users.email',
]
);
$users = Company::scopeCompanyables($users);
if ($request->has('search')) {
$users = $users->where('first_name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('last_name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
}
$users = $users->orderBy('last_name', 'asc')->orderBy('first_name', 'asc');
$users = $users->paginate(50);
foreach ($users as $user) {
$name_str = '';
if ($user->last_name!='') {
$name_str .= e($user->last_name).', ';
}
$name_str .= e($user->first_name);
if ($user->employee_num!='') {
$name_str .= ' (#'.e($user->employee_num).')';
}
$user->use_text = $name_str;
$user->use_image = ($user->present()->gravatar) ? $user->present()->gravatar : null;
}
return (new SelectlistTransformer)->transformSelectlist($users);
}
/**
* Store a newly created resource in storage.
*
@@ -118,7 +190,7 @@ class UsersController extends Controller
$user->password = bcrypt($request->input('password'));
if ($user->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.create.success')));
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.create')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
}
@@ -157,6 +229,9 @@ class UsersController extends Controller
$user->password = bcrypt($request->input('password'));
}
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
if ($user->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
@@ -202,6 +277,6 @@ class UsersController extends Controller
{
$this->authorize('view', User::class);
$assets = Asset::where('assigned_to', '=', $id)->with('model')->get();
return response()->json($assets);
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
}

View File

@@ -115,8 +115,8 @@ class AssetMaintenancesController extends Controller
);
}
if (($maintenance->cost) && (isset($maintenance->asset)) && ($maintenance->asset->assetloc) && ($maintenance->asset->assetloc->currency!='')) {
$maintenance_cost = $maintenance->asset->assetloc->currency.$maintenance->cost;
if (($maintenance->cost) && (isset($maintenance->asset)) && ($maintenance->asset->location) && ($maintenance->asset->location->currency!='')) {
$maintenance_cost = $maintenance->asset->location->currency.$maintenance->cost;
} else {
$maintenance_cost = $settings->default_currency.$maintenance->cost;
}

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;
@@ -34,7 +35,6 @@ class AssetModelsController extends Controller
* the content for the accessories listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see AssetModelsController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
@@ -52,11 +52,9 @@ class AssetModelsController extends Controller
*/
public function create()
{
// Show the page
return view('models/edit')
->with('category_list', Helper::categoryList('asset'))
$category_type = 'asset';
return view('models/edit')->with('category_type',$category_type)
->with('depreciation_list', Helper::depreciationList())
->with('manufacturer_list', Helper::manufacturerList())
->with('item', new AssetModel);
}
@@ -68,7 +66,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
@@ -90,14 +88,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 = slug($image->getClientOriginalName()) . "." . $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?
@@ -157,17 +162,15 @@ class AssetModelsController extends Controller
*/
public function edit($modelId = null)
{
// Check if the model exists
if (is_null($item = AssetModel::find($modelId))) {
// Redirect to the model management page
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
if ($item = AssetModel::find($modelId)) {
$category_type = 'asset';
$view = View::make('models/edit', compact('item','category_type'));
$view->with('depreciation_list', Helper::depreciationList());
return $view;
}
$view = View::make('models/edit', compact('item'));
$view->with('category_list', Helper::categoryList('asset'));
$view->with('depreciation_list', Helper::depreciationList());
$view->with('manufacturer_list', Helper::manufacturerList());
return $view;
return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist'));
}
@@ -180,7 +183,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))) {
@@ -205,14 +208,28 @@ 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_slug($image->getClientOriginalName()) . "." . $image->getClientOriginalExtension();
$path = public_path('uploads/models/');
$old_image = $path.$model->image;
try {
unlink($old_image);
} catch (\Exception $e) {
\Log::error($e);
}
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') == "") {
@@ -245,6 +262,15 @@ class AssetModelsController extends Controller
// Throw an error that this model is associated with assets
return redirect()->route('models.index')->with('error', trans('admin/models/message.assoc_users'));
}
if ($model->image) {
try {
unlink(public_path().'/uploads/models/'.$model->image);
} catch (\Exception $e) {
\Log::error($e);
}
}
// Delete the model
$model->delete();
@@ -352,49 +378,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
@@ -405,13 +388,16 @@ class AssetModelsController extends Controller
*/
public function postBulkEdit(Request $request)
{
$models_raw_array = Input::get('ids');
$models = AssetModel::whereIn('id', $models_raw_array)->get();
$nochange = ['NC' => 'No Change'];
$fieldset_list = $nochange + Helper::customFieldsetList();
$depreciation_list = $nochange + Helper::depreciationList();
$category_list = $nochange + Helper::categoryList('asset');
$manufacturer_list = $nochange + Helper::manufacturerList();
if (is_array($models_raw_array)) {
$models = AssetModel::whereIn('id', $models_raw_array)->get();
$nochange = ['NC' => 'No Change'];
$fieldset_list = $nochange + Helper::customFieldsetList();
$depreciation_list = $nochange + Helper::depreciationList();
$category_list = $nochange + Helper::categoryList('asset');
$manufacturer_list = $nochange + Helper::manufacturerList();
return view('models/bulk-edit', compact('models'))
@@ -419,6 +405,10 @@ class AssetModelsController extends Controller
->with('category_list', $category_list)
->with('fieldset_list', $fieldset_list)
->with('depreciation_list', $depreciation_list);
}
return redirect()->route('models.index')
->with('error', 'You must select at least one model to edit.');
}

View File

@@ -38,6 +38,7 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException;
use TCPDF;
use Validator;
use View;
use App\Models\CheckoutRequest;
/**
* This class controls all actions related to assets for
@@ -110,17 +111,12 @@ class AssetsController extends Controller
$this->authorize('create', Asset::class);
$view = View::make('hardware/edit')
->with('supplier_list', Helper::suppliersList())
->with('company_list', Helper::companyList())
->with('model_list', Helper::modelList())
->with('statuslabel_list', Helper::statusLabelList())
->with('location_list', Helper::locationsList())
->with('item', new Asset)
->with('manufacturer', Helper::manufacturerList()) //handled in modal now?
->with('category', Helper::categoryList('asset')) //handled in modal now?
->with('statuslabel_types', Helper::statusTypeList()) //handled in modal now?
->with('users_list', Helper::usersList())
->with('assets_list', Helper::assetsList())
->with('locations_list', Helper::locationsList());
->with('statuslabel_types', Helper::statusTypeList());
if ($request->has('model_id')) {
$selected_model = AssetModel::find($request->input('model_id'));
@@ -139,17 +135,18 @@ class AssetsController extends Controller
public function store(AssetRequest $request)
{
$this->authorize(Asset::class);
// create a new model instance
$asset = new Asset();
$asset->model()->associate(AssetModel::find(e(Input::get('model_id'))));
$asset->name = Input::get('name');
$asset->serial = Input::get('serial');
$asset->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$asset->model_id = Input::get('model_id');
$asset->order_number = Input::get('order_number');
$asset->notes = Input::get('notes');
$asset->asset_tag = Input::get('asset_tag');
$asset = new Asset();
$asset->model()->associate(AssetModel::find($request->input('model_id')));
$asset->name = $request->input('name');
$asset->serial = $request->input('serial');
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$asset->model_id = $request->input('model_id');
$asset->order_number = $request->input('order_number');
$asset->notes = $request->input('notes');
$asset->asset_tag = $request->input('asset_tag');
$asset->user_id = Auth::id();
$asset->archived = '0';
$asset->physical = '1';
@@ -164,8 +161,8 @@ class AssetsController extends Controller
$asset->rtd_location_id = request('rtd_location_id', null);
// Create the image (if one was chosen.)
if (Input::has('image')) {
$image = Input::get('image');
if ($request->has('image')) {
$image = $request->input('image');
// After modification, the image is prefixed by mime info like the following:
// data:image/jpeg;base64,; This causes the image library to be unhappy, so we need to remove it.
@@ -259,14 +256,8 @@ class AssetsController extends Controller
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('statuslabel_types', Helper::statusTypeList());
}
@@ -404,9 +395,8 @@ class AssetsController extends Controller
$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');
$logaction->logaction('deleted');
// Redirect to the asset management page
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
}
@@ -430,10 +420,7 @@ class AssetsController extends Controller
$this->authorize('checkout', $asset);
// 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('locations_list', Helper::locationsList());
return view('hardware/checkout', compact('asset'));
}
/**
@@ -458,7 +445,7 @@ class AssetsController extends Controller
if (request('assigned_user')) {
$target = User::find(request('assigned_user'));
} elseif (request('assigned_asset')) {
$target = Asset::find(request('assigned_asset'));
$target = Asset::where('id','!=',$assetId)->find(request('assigned_asset'));
} elseif (request('assigned_location')) {
$target = Location::find(request('assigned_location'));
}
@@ -476,6 +463,17 @@ class AssetsController extends Controller
} else {
$expected_checkin = '';
}
// Set the location ID to the RTD location id if there is one
if ($asset->rtd_location_id!='') {
$asset->location_id = $target->rtd_location_id;
}
// Overwrite that if the target has a location ID though
if ($target->location_id!='') {
$asset->location_id = $target->location_id;
}
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e(Input::get('note')), Input::get('name'))) {
// Redirect to the new asset page
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkout.success'));
@@ -547,6 +545,11 @@ class AssetsController extends Controller
if (Input::has('status_id')) {
$asset->status_id = e(Input::get('status_id'));
}
if (Input::has('location_id')) {
$asset->location_id = e(Input::get('location_id'));
}
// Was the asset updated?
if ($asset->save()) {
$logaction = $asset->logCheckin($target, e(request('note')));
@@ -558,6 +561,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)) && (!empty($user->email)) && (!config('app.lock_passwords'))) {
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
@@ -592,15 +598,17 @@ 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();
if (isset($asset)) {
if (!is_null($asset->assetloc)) {
$use_currency = $asset->assetloc->currency;
$audit_log = Actionlog::where('action_type', '=', 'audit')
->where('item_id', '=', $assetId)
->where('item_type', '=', Asset::class)
->orderBy('created_at', 'DESC')->first();
if ($asset->location) {
$use_currency = $asset->location->currency;
} else {
if ($settings->default_currency!='') {
$use_currency = $settings->default_currency;
@@ -618,7 +626,7 @@ class AssetsController extends Controller
->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')));
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
/**
@@ -634,7 +642,7 @@ 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).'-'.str_slug($asset->id).'.png';
@@ -672,8 +680,12 @@ class AssetsController extends Controller
$header = ['Content-type' => 'image/png'];
return response()->file($barcode_file, $header);
} else {
// Calculate barcode width in pixel based on label width (inch)
$barcode_width = ($settings->labels_width - $settings->labels_display_sgutter) * 96.000000000001;
$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,($barcode_width < 300 ? $barcode_width : 300),50);
file_put_contents($barcode_file, $barcode_obj->getPngData());
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
}
@@ -705,18 +717,9 @@ class AssetsController extends Controller
$asset->assigned_to = '';
return view('hardware/edit')
->with('supplier_list', Helper::suppliersList())
->with('model_list', Helper::modelList())
->with('statuslabel_list', Helper::statusLabelList())
->with('statuslabel_types', Helper::statusTypeList())
->with('assigned_to', Helper::usersList())
->with('item', $asset)
->with('locations_list', Helper::locationsList())
->with('manufacturer', Helper::manufacturerList())
->with('category', Helper::categoryList('asset'))
->with('users_list', Helper::usersList())
->with('assets_list', Helper::assetsList())
->with('company_list', Helper::companyList());
->with('item', $asset);
}
/**
@@ -908,27 +911,23 @@ class AssetsController extends Controller
if (!$asset = Asset::find($assetId)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('update', $asset);
$destinationPath = config('app.private_uploads').'/assets';
if (Input::hasFile('assetfile')) {
foreach (Input::file('assetfile') as $file) {
if ($request->hasFile('image')) {
foreach ($request->file('image') as $file) {
$extension = $file->getClientOriginalExtension();
$filename = 'hardware-'.$asset->id.'-'.str_random(8);
$filename .= '-'.str_slug($file->getClientOriginalName()).'.'.$extension;
$upload_success = $file->move($destinationPath, $filename);
//Log the deletion of seats to the log
$file->move($destinationPath, $filename);
$asset->logUpload($filename, e(Input::get('notes')));
}
} else {
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
}
if ($upload_success) {
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
}
return redirect()->back()->with('error', trans('admin/hardware/message.upload.error'));
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
}
/**
@@ -958,11 +957,9 @@ 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'));
// Redirect to the hardware management page
return redirect()->route('hardware.index')->with('error', $error);
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
/**
@@ -1010,8 +1007,6 @@ class AssetsController extends Controller
{
$this->authorize('update', Asset::class);
if (!$request->has('ids')) {
return redirect()->back()->with('error', 'No assets selected');
}
@@ -1028,10 +1023,9 @@ class AssetsController extends Controller
return view('hardware/labels')
->with('assets', Asset::find($asset_ids))
->with('settings', Setting::getSettings())
->with('count', $count)
->with('settings', Setting::getSettings());
->with('count', $count);
} elseif ($request->input('bulk_actions')=='delete') {
$assets = Asset::with('assignedTo', 'assetloc')->find($asset_ids);
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
@@ -1040,10 +1034,7 @@ class AssetsController extends Controller
} elseif ($request->input('bulk_actions')=='edit') {
return view('hardware/bulk')
->with('assets', request('ids'))
->with('supplier_list', Helper::suppliersList())
->with('statuslabel_list', Helper::statusLabelList())
->with('location_list', Helper::locationsList())
->with('models_list', Helper::modelList())
->with(
'companies_list',
array('' => '') + array('clear' => trans('general.remove_company')) + Helper::companyList()
@@ -1160,10 +1151,9 @@ class AssetsController extends Controller
{
$this->authorize('checkout', Asset::class);
// Filter out assets that are not deployable.
$assets_list = Company::scopeCompanyables(Asset::RTD()->get(), 'assets.company_id')->pluck('detailed_name', 'id')->toArray();
return view('hardware/bulk-checkout')
->with('users_list', Helper::usersList())
->with('assets_list', $assets_list);
->with('users_list', Helper::usersList());
}
public function postBulkCheckout(Request $request)
@@ -1175,6 +1165,9 @@ class AssetsController extends Controller
$user = User::find(e(Input::get('assigned_to')));
$admin = Auth::user();
if (!is_array(Input::get('selected_assets'))) {
return redirect()->route('hardware/bulkcheckout')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
}
$asset_ids = array_filter(Input::get('selected_assets'));
if ((Input::has('checkout_at')) && (Input::get('checkout_at')!= date("Y-m-d"))) {
@@ -1212,21 +1205,21 @@ class AssetsController extends Controller
}
public function quickScan(Request $request)
public function quickScan()
{
$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());
return view('hardware/quickscan')->with('next_audit_date', $dt);
}
public function audit(Request $request, $id)
public function audit($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)->with('locations_list', Helper::locationsList());
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list');
}
public function auditStore(Request $request, $id)
@@ -1251,4 +1244,14 @@ class AssetsController extends Controller
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success'));
}
}
public function getRequestedIndex($id = null)
{
if ($id) {
$requestedItems = CheckoutRequest::where('user_id', $id)->with('user', 'requestedItem')->get();
}
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->get();
return view('hardware/requested', compact('requestedItems'));
}
}

View File

@@ -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;
}
}

View File

@@ -15,6 +15,8 @@ use Lang;
use Redirect;
use Str;
use View;
use Image;
use App\Http\Requests\ImageUploadRequest;
/**
* This class controls all actions related to Categories for
@@ -67,7 +69,7 @@ class CategoriesController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
// create a new model instance
$category = new Category();
@@ -80,6 +82,18 @@ class CategoriesController extends Controller
$category->checkin_email = $request->input('checkin_email', '0');
$category->user_id = Auth::id();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/categories/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$category->image = $file_name;
}
if ($category->save()) {
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.create.success'));
}
@@ -98,10 +112,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();
@@ -120,7 +132,7 @@ class CategoriesController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @since [v1.0]
*/
public function update(Request $request, $categoryId = null)
public function update(ImageUploadRequest $request, $categoryId = null)
{
// Check if the blog post exists
if (is_null($category = Category::find($categoryId))) {
@@ -138,6 +150,20 @@ class CategoriesController extends Controller
$category->require_acceptance = $request->input('require_acceptance', '0');
$category->checkin_email = $request->input('checkin_email', '0');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/categories/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$category->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$category->image = null;
}
if ($category->save()) {
// Redirect to the new category page
return redirect()->route('categories.index')->with('success', trans('admin/categories/message.update.success'));
@@ -158,22 +184,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'));
}

View File

@@ -7,6 +7,8 @@ use Lang;
use Redirect;
use View;
use Illuminate\Http\Request;
use Image;
use App\Http\Requests\ImageUploadRequest;
/**
* This controller handles all actions related to Companies for
@@ -50,11 +52,22 @@ final class CompaniesController extends Controller
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$company = new Company;
$company->name = $request->input('name');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/companies/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$company->image = $file_name;
}
if ($company->save()) {
return redirect()->route('companies.index')
->with('success', trans('admin/companies/message.create.success'));
@@ -89,7 +102,7 @@ final class CompaniesController extends Controller
* @param int $companyId
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, $companyId)
public function update(ImageUploadRequest $request, $companyId)
{
if (is_null($company = Company::find($companyId))) {
return redirect()->route('companies.index')->with('error', trans('admin/companies/message.does_not_exist'));
@@ -97,6 +110,20 @@ final class CompaniesController extends Controller
$company->name = $request->input('name');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/companies/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$company->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$company->image = null;
}
if ($company->save()) {
return redirect()->route('companies.index')
->with('success', trans('admin/companies/message.update.success'));

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Company;
use App\Models\Component;
use App\Models\CustomField;
@@ -21,6 +22,7 @@ use View;
use Validator;
use Illuminate\Http\Request;
use Gate;
use Image;
/**
* This class controls all actions related to Components for
@@ -57,12 +59,9 @@ class ComponentsController extends Controller
public function create()
{
$this->authorize('create', Component::class);
// Show the page
return view('components/edit')
->with('item', new Component)
->with('category_list', Helper::categoryList('component'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList());
$category_type = 'component';
return view('components/edit')->with('category_type',$category_type)
->with('item', new Component);
}
@@ -74,7 +73,7 @@ class ComponentsController extends Controller
* @since [v3.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Component::class);
$component = new Component();
@@ -90,6 +89,18 @@ class ComponentsController extends Controller
$component->qty = $request->input('qty');
$component->user_id = Auth::id();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$component->image = $file_name;
}
if ($component->save()) {
return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success'));
}
@@ -107,16 +118,18 @@ class ComponentsController extends Controller
*/
public function edit($componentId = null)
{
if (is_null($item = Component::find($componentId))) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
if ($item = Component::find($componentId)) {
$this->authorize('update', $item);
$category_type = 'component';
return view('components/edit', compact('item'))->with('category_type', $category_type);
}
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
$this->authorize('update', $item);
return view('components/edit', compact('item'))
->with('category_list', Helper::categoryList('component'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList());
}
@@ -129,7 +142,7 @@ class ComponentsController extends Controller
* @since [v3.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function update($componentId = null)
public function update(ImageUploadRequest $request, $componentId = null)
{
if (is_null($component = Component::find($componentId))) {
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
@@ -150,6 +163,19 @@ class ComponentsController extends Controller
$component->purchase_cost = request('purchase_cost');
$component->qty = Input::get('qty');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/components/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$component->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$component->image = null;
}
if ($component->save()) {
return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success'));
}
@@ -228,7 +254,7 @@ class ComponentsController extends Controller
return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found'));
}
$this->authorize('checkout', $component);
return view('components/checkout', compact('component'))->with('assets_list', Helper::detailedAssetList());
return view('components/checkout', compact('component'));
}
/**
@@ -288,35 +314,4 @@ class ComponentsController extends Controller
}
/**
* 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;
}
}

View File

@@ -19,6 +19,8 @@ use Slack;
use Str;
use View;
use Gate;
use Image;
use App\Http\Requests\ImageUploadRequest;
/**
* This controller handles all actions related to Consumables for
@@ -54,13 +56,9 @@ class ConsumablesController extends Controller
public function create()
{
$this->authorize('create', Consumable::class);
// Show the page
return view('consumables/edit')
->with('item', new Consumable)
->with('category_list', Helper::categoryList('consumable'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList())
->with('manufacturer_list', Helper::manufacturerList());
$category_type = 'consumable';
return view('consumables/edit')->with('category_type', $category_type)
->with('item', new Consumable);
}
@@ -72,24 +70,36 @@ class ConsumablesController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function store()
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Consumable::class);
$consumable = new Consumable();
$consumable->name = Input::get('name');
$consumable->category_id = Input::get('category_id');
$consumable->location_id = Input::get('location_id');
$consumable->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$consumable->order_number = Input::get('order_number');
$consumable->min_amt = Input::get('min_amt');
$consumable->manufacturer_id = Input::get('manufacturer_id');
$consumable->model_number = Input::get('model_number');
$consumable->item_no = Input::get('item_no');
$consumable->purchase_date = Input::get('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat(Input::get('purchase_cost'));
$consumable->qty = Input::get('qty');
$consumable->name = $request->input('name');
$consumable->category_id = $request->input('category_id');
$consumable->location_id = $request->input('location_id');
$consumable->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$consumable->order_number = $request->input('order_number');
$consumable->min_amt = $request->input('min_amt');
$consumable->manufacturer_id = $request->input('manufacturer_id');
$consumable->model_number = $request->input('model_number');
$consumable->item_no = $request->input('item_no');
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat($request->input('purchase_cost'));
$consumable->qty = $request->input('qty');
$consumable->user_id = Auth::id();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/consumables/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$consumable->image = $file_name;
}
if ($consumable->save()) {
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.create.success'));
}
@@ -109,17 +119,14 @@ class ConsumablesController extends Controller
*/
public function edit($consumableId = null)
{
if (is_null($item = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
if ($item = Consumable::find($consumableId)) {
$this->authorize($item);
$category_type = 'consumable';
return view('consumables/edit', compact('item'))->with('category_type', $category_type);
}
$this->authorize($item);
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
return view('consumables/edit', compact('item'))
->with('category_list', Helper::categoryList('consumable'))
->with('company_list', Helper::companyList())
->with('location_list', Helper::locationsList())
->with('manufacturer_list', Helper::manufacturerList());
}
@@ -132,7 +139,7 @@ class ConsumablesController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function update($consumableId = null)
public function update(ImageUploadRequest $request, $consumableId = null)
{
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
@@ -140,19 +147,32 @@ class ConsumablesController extends Controller
$this->authorize($consumable);
$consumable->name = Input::get('name');
$consumable->category_id = Input::get('category_id');
$consumable->location_id = Input::get('location_id');
$consumable->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$consumable->order_number = Input::get('order_number');
$consumable->min_amt = Input::get('min_amt');
$consumable->manufacturer_id = Input::get('manufacturer_id');
$consumable->model_number = Input::get('model_number');
$consumable->item_no = Input::get('item_no');
$consumable->purchase_date = Input::get('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat(Input::get('purchase_cost'));
$consumable->name = $request->input('name');
$consumable->category_id = $request->input('category_id');
$consumable->location_id = $request->input('location_id');
$consumable->company_id = Company::getIdForCurrentUser($request->input('company_id'));
$consumable->order_number = $request->input('order_number');
$consumable->min_amt = $request->input('min_amt');
$consumable->manufacturer_id = $request->input('manufacturer_id');
$consumable->model_number = $request->input('model_number');
$consumable->item_no = $request->input('item_no');
$consumable->purchase_date = $request->input('purchase_date');
$consumable->purchase_cost = Helper::ParseFloat(Input::get('purchase_cost'));
$consumable->qty = Helper::ParseFloat(Input::get('qty'));
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/consumables/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$consumable->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$consumable->image = null;
}
if ($consumable->save()) {
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.update.success'));
}
@@ -194,7 +214,7 @@ class ConsumablesController extends Controller
if (isset($consumable->id)) {
return view('consumables/view', compact('consumable'));
}
return redirect()->route('consumables')->with('error', trans('admin/consumables/message.does_not_exist', compact('id')));
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist', compact('id')));
}
/**
@@ -209,10 +229,10 @@ class ConsumablesController extends Controller
public function getCheckout($consumableId)
{
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
$this->authorize('checkout', $consumable);
return view('consumables/checkout', compact('consumable'))->with('users_list', Helper::usersList());
return view('consumables/checkout', compact('consumable'));
}
/**
@@ -238,7 +258,7 @@ class ConsumablesController extends Controller
// Check if the user exists
if (is_null($user = User::find($assigned_to))) {
// Redirect to the consumable management page with error
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.user_does_not_exist'));
return redirect()->route('checkout/consumable', $consumable)->with('error', trans('admin/consumables/message.checkout.user_does_not_exist'));
}
// Update the consumable data
@@ -259,7 +279,7 @@ class ConsumablesController extends Controller
$data['note'] = $logaction->note;
$data['require_acceptance'] = $consumable->requireAcceptance();
if (($consumable->requireAcceptance()=='1') || ($consumable->getEula())) {
if ((($consumable->requireAcceptance()=='1') || ($consumable->getEula())) && $user->email!='') {
Mail::send('emails.accept-asset', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);

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);

View File

@@ -6,6 +6,8 @@ use Illuminate\Http\Request;
use App\Models\Department;
use App\Helpers\Helper;
use Auth;
use Image;
use App\Http\Requests\ImageUploadRequest;
class DepartmentsController extends Controller
{
@@ -27,13 +29,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);
}
@@ -45,7 +45,7 @@ class DepartmentsController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$this->authorize('create', Department::class);
$department = new Department;
@@ -53,12 +53,21 @@ class DepartmentsController extends Controller
$department->user_id = Auth::user()->id;
$department->manager_id = ($request->has('manager_id' ) ? $request->input('manager_id') : null);
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/departments/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$department->image = $file_name;
}
if ($department->save()) {
return redirect()->route("departments.index")->with('success', trans('admin/departments/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($department->getErrors());
}
/**
@@ -91,10 +100,7 @@ class DepartmentsController extends Controller
*/
public function create()
{
return view('departments/edit')->with('item', new Department)
->with('manager_list', Helper::managerList())
->with('location_list', Helper::locationsList())
->with('company_list', Helper::companyList());
return view('departments/edit')->with('item', new Department);
}
@@ -135,30 +141,36 @@ class DepartmentsController extends Controller
if (is_null($item = Department::find($id))) {
return redirect()->back()->with('error', trans('admin/locations/message.does_not_exist'));
}
return view('departments/edit', compact('item'))
->with('manager_list', Helper::managerList())
->with('location_list', Helper::locationsList())
->with('company_list', Helper::companyList());
return view('departments/edit', compact('item'));
}
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());
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/departments/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$department->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$department->image = null;
}
$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());
}
}

View File

@@ -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'));
}
}

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')));
}
}

View File

@@ -67,10 +67,7 @@ class LicensesController extends Controller
return view('licenses/edit')
//->with('license_options',$license_options)
->with('depreciation_list', Helper::depreciationList())
->with('supplier_list', Helper::suppliersList())
->with('maintained_list', $maintained_list)
->with('company_list', Helper::companyList())
->with('manufacturer_list', Helper::manufacturerList())
->with('item', new License);
}
@@ -144,10 +141,7 @@ class LicensesController extends Controller
return view('licenses/edit', compact('item'))
->with('depreciation_list', Helper::depreciationList())
->with('supplier_list', Helper::suppliersList())
->with('company_list', Helper::companyList())
->with('maintained_list', $maintained_list)
->with('manufacturer_list', Helper::manufacturerList());
->with('maintained_list', $maintained_list);
}
@@ -187,6 +181,7 @@ class LicensesController extends Controller
$license->termination_date = $request->input('termination_date');
$license->seats = e($request->input('seats'));
$license->manufacturer_id = $request->input('manufacturer_id');
$license->supplier_id = $request->input('supplier_id');
if ($license->save()) {
return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success'));
@@ -253,9 +248,7 @@ class LicensesController extends Controller
}
$this->authorize('checkout', $licenseSeat);
return view('licenses/checkout', compact('licenseSeat'))
->with('users_list', Helper::usersList())
->with('asset_list', Helper::detailedAssetList());
return view('licenses/checkout', compact('licenseSeat'));
}
@@ -440,17 +433,15 @@ class LicensesController extends Controller
public function show($licenseId = null)
{
$license = License::find($licenseId);
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
$license = License::with('assignedusers', 'licenseSeats.user', 'licenseSeats.asset')->find($licenseId);
if (isset($license->id)) {
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
if ($license) {
$this->authorize('view', $license);
return view('licenses/view', compact('license'));
}
$error = trans('admin/licenses/message.does_not_exist', compact('id'));
return redirect()->route('licenses.index')->with('error', $error);
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', compact('id')));
}
public function getClone($licenseId = null)
{
@@ -473,11 +464,8 @@ class LicensesController extends Controller
// Show the page
return view('licenses/edit')
->with('depreciation_list', Helper::depreciationList())
->with('supplier_list', Helper::suppliersList())
->with('item', $license)
->with('maintained_list', $maintained_list)
->with('company_list', Helper::companyList())
->with('manufacturer_list', Helper::manufacturerList());
->with('maintained_list', $maintained_list);
}
@@ -591,61 +579,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.

View File

@@ -16,6 +16,8 @@ use Validator;
use View;
use Auth;
use Symfony\Component\HttpFoundation\JsonResponse;
use Image;
use App\Http\Requests\ImageUploadRequest;
/**
* This controller handles all actions related to Locations for
@@ -63,8 +65,7 @@ class LocationsController extends Controller
return view('locations/edit')
->with('location_options', $location_options)
->with('item', new Location)
->with('manager_list', Helper::managerList());
->with('item', new Location);
}
@@ -77,21 +78,33 @@ class LocationsController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function store()
public function store(ImageUploadRequest $request)
{
$location = new Location();
$location->name = Input::get('name');
$location->parent_id = Input::get('parent_id', null);
$location->currency = Input::get('currency', '$');
$location->address = Input::get('address');
$location->address2 = Input::get('address2');
$location->city = Input::get('city');
$location->state = Input::get('state');
$location->country = Input::get('country');
$location->zip = Input::get('zip');
$location->manager_id = Input::get('manager_id');
$location->name = $request->input('name');
$location->parent_id = $request->input('parent_id', null);
$location->currency = $request->input('currency', '$');
$location->address = $request->input('address');
$location->address2 = $request->input('address2');
$location->city = $request->input('city');
$location->state = $request->input('state');
$location->country = $request->input('country');
$location->zip = $request->input('zip');
$location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id');
$location->user_id = Auth::id();
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/locations/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$location->image = $file_name;
}
if ($location->save()) {
return redirect()->route("locations.index")->with('success', trans('admin/locations/message.create.success'));
}
@@ -107,7 +120,7 @@ class LocationsController extends Controller
* @since [v1.0]
* @return String JSON
*/
public function apiStore()
public function apiStore(Request $request)
{
$new['currency']=Setting::first()->default_currency;
@@ -115,13 +128,13 @@ class LocationsController extends Controller
$location = new Location();
// Save the location data
$location->name = Input::get('name');
$location->name = $request->input('name');
$location->currency = Setting::first()->default_currency; //e(Input::get('currency'));
$location->address = ''; //e(Input::get('address'));
// $location->address2 = e(Input::get('address2'));
$location->city = Input::get('city');
$location->city = $request->input('city');
$location->state = '';//e(Input::get('state'));
$location->country = Input::get('country');
$location->country = $request->input('country');
// $location->zip = e(Input::get('zip'));
$location->user_id = Auth::id();
@@ -147,7 +160,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 +169,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());
@@ -172,32 +184,43 @@ class LocationsController extends Controller
* @since [v1.0]
* @return \Illuminate\Http\RedirectResponse
*/
public function update($locationId = null)
public function update(ImageUploadRequest $request, $locationId = null)
{
// 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
$location->name = Input::get('name');
$location->parent_id = Input::get('parent_id', null);
$location->currency = Input::get('currency', '$');
$location->address = Input::get('address');
$location->address2 = Input::get('address2');
$location->city = Input::get('city');
$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->name = $request->input('name');
$location->parent_id = $request->input('parent_id', null);
$location->currency = $request->input('currency', '$');
$location->address = $request->input('address');
$location->address2 = $request->input('address2');
$location->city = $request->input('city');
$location->state = $request->input('state');
$location->country = $request->input('country');
$location->zip = $request->input('zip');
$location->ldap_ou = $request->input('ldap_ou');
$location->manager_id = $request->input('manager_id');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/locations/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$location->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$location->image = null;
}
// Was the location updated?
if ($location->save()) {
// Redirect to the saved location page
return redirect()->route("locations.index")->with('success', trans('admin/locations/message.update.success'));
}
// Redirect to the location management page
return redirect()->back()->withInput()->withInput()->withErrors($location->getErrors());
}
@@ -211,21 +234,22 @@ class LocationsController extends Controller
*/
public function destroy($locationId)
{
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
// Redirect to the blogs management page
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) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_child_loc'));
} elseif ($location->assets->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
} elseif ($location->assignedassets->count() > 0) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
} else {
$location->delete();
return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success'));
@@ -249,11 +273,8 @@ class LocationsController extends Controller
if (isset($location->id)) {
return view('locations/view', compact('location'));
}
// Prepare the error message
$error = trans('admin/locations/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('locations.index')->with('error', $error);
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist', compact('id')));
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Models\CustomField;
use App\Models\Manufacturer;
use Auth;
@@ -13,6 +14,7 @@ use Redirect;
use Str;
use View;
use Illuminate\Http\Request;
use Image;
/**
* This controller handles all actions related to Manufacturers for
@@ -60,7 +62,7 @@ class ManufacturersController extends Controller
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
$manufacturer = new Manufacturer;
@@ -72,6 +74,18 @@ class ManufacturersController extends Controller
$manufacturer->support_email = $request->input('support_email');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_slug($image->getClientOriginalName()).".".$image->getClientOriginalExtension();
$path = public_path('uploads/manufacturers/'.$file_name);
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$manufacturer->image = $file_name;
}
if ($manufacturer->save()) {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.create.success'));
@@ -124,6 +138,29 @@ class ManufacturersController extends Controller
$manufacturer->support_phone = $request->input('support_phone');
$manufacturer->support_email = $request->input('support_email');
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_slug($image->getClientOriginalName()).".".$image->getClientOriginalExtension();
$path = public_path('uploads/manufacturers/'.$file_name);
$old_image = $path.$manufacturer->image;
try {
unlink($old_image);
} catch (\Exception $e) {
\Log::error($e);
}
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$manufacturer->image = $file_name;
} elseif ($request->input('image_delete')=='1') {
$manufacturer->image = null;
}
if ($manufacturer->save()) {
return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.update.success'));
}
@@ -150,6 +187,16 @@ class ManufacturersController extends Controller
// Redirect to the asset management page
return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.assoc_users'));
}
if ($manufacturer->image) {
try {
unlink(public_path().'/uploads/manufacturers/'.$manufacturer->image);
} catch (\Exception $e) {
\Log::error($e);
}
}
// Delete the manufacturer
$manufacturer->delete();
// Redirect to the manufacturers management page
@@ -158,11 +205,10 @@ class ManufacturersController extends Controller
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the manufacturers detail listing, which is generated in getDatatable.
* the content for the manufacturers detail listing, which is generated via API.
* This data contains a listing of all assets that belong to that manufacturer.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getDataView()
* @param int $manufacturerId
* @since [v1.0]
* @return \Illuminate\Contracts\View\View
@@ -174,154 +220,13 @@ class ManufacturersController extends Controller
if (isset($manufacturer->id)) {
return view('manufacturers/view', compact('manufacturer'));
}
// Prepare the error message
$error = trans('admin/manufacturers/message.does_not_exist', compact('id'));
$error = trans('admin/manufacturers/message.does_not_exist');
// Redirect to the user management page
return redirect()->route('manufacturers')->with('error', $error);
return redirect()->route('manufacturers.index')->with('error', $error);
}
/**
* Generates the JSON used to display the manufacturer detail.
* This JSON returns data on all of the assets with the specified
* manufacturer ID number.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getView()
* @param int $manufacturerId
* @param string $itemType
* @param Request $request
* @return String JSON* @since [v1.0]
*/
public function getDataView($manufacturerId, $itemType = null, Request $request)
{
$manufacturer = Manufacturer::find($manufacturerId);
switch ($itemType) {
case "assets":
return $this->getDataAssetsView($manufacturer, $request);
case "licenses":
return $this->getDataLicensesView($manufacturer, $request);
case "accessories":
return $this->getDataAccessoriesView($manufacturer, $request);
case "consumables":
return $this->getDataConsumablesView($manufacturer, $request);
}
return "We shouldn't be here";
}
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;
}
}

View File

@@ -30,8 +30,7 @@ class ProfileController extends Controller
public function getIndex()
{
$user = Auth::user();
$location_list = Helper::locationsList();
return view('account/profile', compact('user'))->with('location_list', $location_list);
return view('account/profile', compact('user'));
}
/**
@@ -143,5 +142,25 @@ class ProfileController extends Controller
}
/**
* Save the menu state of open/closed when the user clicks on the hamburger
* menu.
*
* This URL is triggered via jquery in
* resources/views/layouts/default.blade.php
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return View
*/
public function getMenuState(Request $request) {
if ($request->input('state')=='open') {
$request->session()->put('menu_state', 'open');
} else {
$request->session()->put('menu_state', 'closed');
}
}
}

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', 'location','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->location) ? e($asset->location->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( 'assignedTo', 'assetstatus', 'defaultLoc', 'assetloc', 'assetlog', 'company', 'model.category', 'model.depreciation')
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'assetlog', 'company', 'model.category', 'model.depreciation')
->orderBy('created_at', 'DESC')->get();
return view('reports/depreciation', compact('assets'));
@@ -241,7 +270,7 @@ class ReportsController extends Controller
$row[] = ''; // Empty string if unassigned
}
if (( $asset->assigned_to > 0 ) && ( $location = $asset->assetLoc )) {
if (( $asset->assigned_to > 0 ) && ( $location = $asset->location )) {
if ($location->city) {
$row[] = e($location->city) . ', ' . e($location->state);
} elseif ($location->name) {
@@ -253,8 +282,8 @@ class ReportsController extends Controller
$row[] = ''; // Empty string if location is not set
}
if ($asset->assetloc) {
$currency = e($asset->assetloc->currency);
if ($asset->location) {
$currency = e($asset->location->currency);
} else {
$currency = e(Setting::first()->default_currency);
}
@@ -390,7 +419,7 @@ class ReportsController extends Controller
*/
public function postCustom()
{
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assignedTo', 'assetloc', 'defaultLoc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assignedTo', 'location', 'defaultLoc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
$customfields = CustomField::get();
$rows = [ ];
@@ -533,8 +562,8 @@ class ReportsController extends Controller
}
if (e(Input::get('location')) == '1') {
if($asset->assetLoc) {
$show_loc = $asset->assetLoc->present()->name();
if($asset->location) {
$show_loc = $asset->location->present()->name();
} else {
$show_loc = 'Default location '.$asset->rtd_location_id.' is invalid';
}
@@ -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
}
@@ -553,7 +582,7 @@ 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->checkedOutToUser()) {
$row[] = '"' .e($asset->assignedTo->username). '"';
$row[] = '"' .e($asset->assignedto->username). '"';
} else {
$row[] = ''; // Empty string if unassigned
}
@@ -562,7 +591,7 @@ 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->checkedOutToUser()) {
$row[] = '"' .e($asset->assignedTo->employee_num). '"';
$row[] = '"' .e($asset->assignedto->employee_num). '"';
} else {
$row[] = ''; // Empty string if unassigned
}

View File

@@ -21,6 +21,7 @@ use App\Models\User;
use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsLdapRequest;
use App\Helpers\Helper;
/**
* This controller handles all actions related to Settings for
@@ -136,28 +137,6 @@ class SettingsController extends Controller
->with('section', 'Pre-Flight Check');
}
/**
* Test the email configuration
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function ajaxTestEmail()
{
try {
Mail::send('emails.test', [], function ($m) {
$m->to(config('mail.from.address'), config('mail.from.name'));
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.test_email'));
});
return 'success';
} catch (Exception $e) {
return 'error';
}
}
/**
* Save the first admin user from Setup.
@@ -263,8 +242,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');
}
@@ -391,6 +370,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
@@ -414,7 +394,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);
@@ -846,6 +826,7 @@ class SettingsController extends Controller
$setting->is_ad = $request->input('is_ad', '0');
$setting->ldap_tls = $request->input('ldap_tls', '0');
$setting->ldap_pw_sync = $request->input('ldap_pw_sync', '0');
$setting->custom_forgot_pass_url = $request->input('custom_forgot_pass_url');
if ($setting->save()) {
return redirect()->route('settings.index')
@@ -907,12 +888,30 @@ class SettingsController extends Controller
public function postBackups()
{
if (!config('app.lock_passwords')) {
Artisan::call('backup:run');
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.generated'));
} else {
return redirect()->to("settings.backups.index")->with('error', trans('general.feature_disabled'));
}
$output = Artisan::output();
// Backup completed
if (!preg_match('/failed/', $output)) {
return redirect()->route('settings.backups.index')
->with('success', trans('admin/settings/message.backup.generated'));
}
$formatted_output = str_replace('Backup completed!', '', $output);
$output_split = explode('...', $formatted_output);
if (array_key_exists(2, $output_split)) {
return redirect()->route("settings.backups.index")->with('error', $output_split[2]);
}
return redirect()->route("settings.backups.index")->with('error', $formatted_output);
}
return redirect()->route("settings.backups.index")->with('error', trans('general.feature_disabled'));
}
@@ -1023,4 +1022,28 @@ class SettingsController extends Controller
public function api() {
return view('settings.api');
}
/**
* Test the email configuration
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function ajaxTestEmail()
{
try {
Mail::send('emails.test', [], function ($m) {
$m->to(config('mail.from.address'), config('mail.from.name'));
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.test_email'));
});
return response()->json(Helper::formatStandardApiResponse('success', null, 'Maiol sent!'));
} catch (Exception $e) {
return response()->json(Helper::formatStandardApiResponse('success', null, $e->getMessage()));
}
}
}

View File

@@ -32,18 +32,17 @@ class StatuslabelsController extends Controller
public function index()
{
return view('statuslabels/index', compact('statuslabels'));
return view('statuslabels.index', compact('statuslabels'));
}
public function show($id)
{
$statuslabel = Statuslabel::find($id);
if (isset($statuslabel->id)) {
return view('statuslabels/view', compact('statuslabel'));
if ($statuslabel = Statuslabel::find($id)) {
return view('statuslabels.view')->with('statuslabel', $statuslabel);
}
return redirect()->route('statuslabels.index')->with('error', trans('admin/locations/message.does_not_exist', compact('id')));
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.does_not_exist', compact('id')));
}
@@ -200,17 +199,15 @@ class StatuslabelsController extends Controller
{
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.not_found'));
}
if ($statuslabel->has_assets() == 0) {
// Check that there are no assets associated
if ($statuslabel->assets()->count() == 0) {
$statuslabel->delete();
// Redirect to the statuslabels management page
return redirect()->route('statuslabels.index')->with('success', trans('admin/statuslabels/message.delete.success'));
}
// Redirect to the asset management page
return redirect()->route('statuslabels.index')->with('error', trans('admin/statuslabels/message.assoc_assets'));
}

View File

@@ -13,6 +13,7 @@ use Str;
use View;
use Auth;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -56,7 +57,7 @@ class SuppliersController extends Controller
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(ImageUploadRequest $request)
{
// Create a new supplier
$supplier = new Supplier;
@@ -76,19 +77,18 @@ class SuppliersController extends Controller
$supplier->url = $supplier->addhttp(request('url'));
$supplier->user_id = Auth::id();
if (Input::file('image')) {
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/suppliers/'.$file_name);
Image::make($image->getRealPath())->resize(300, null, function ($constraint) {
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$supplier->image = $file_name;
$supplier->image = $file_name;
}
if ($supplier->save()) {
// 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());
@@ -135,7 +135,7 @@ class SuppliersController extends Controller
* @param int $supplierId
* @return \Illuminate\Http\RedirectResponse
*/
public function update($supplierId = null, Request $request)
public function update($supplierId = null, ImageUploadRequest $request)
{
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
@@ -158,18 +158,17 @@ class SuppliersController extends Controller
$supplier->url = $supplier->addhttp(request('url'));
$supplier->notes = request('notes');
if (Input::file('image')) {
if ($request->file('image')) {
$image = $request->file('image');
$file_name = str_random(25).".".$image->getClientOriginalExtension();
$path = public_path('uploads/suppliers/'.$file_name);
Image::make($image->getRealPath())->resize(300, null, function ($constraint) {
Image::make($image->getRealPath())->resize(200, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$supplier->image = $file_name;
}
if (request('image_delete') == 1 && $request->file('image') == "") {
} elseif ($request->input('image_delete')=='1') {
$supplier->image = null;
}
@@ -189,23 +188,29 @@ class SuppliersController extends Controller
*/
public function destroy($supplierId)
{
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
// Redirect to the suppliers page
if (is_null($supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances','assets','licenses')->find($supplierId))) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.not_found'));
}
if ($supplier->num_assets() == 0) {
// Delete the supplier
$supplier->delete();
// Redirect to the suppliers management page
return redirect()->route('suppliers.index')->with(
'success',
trans('admin/suppliers/message.delete.success')
);
if ($supplier->assets_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count]));
}
// Redirect to the asset management page
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.assoc_users'));
if ($supplier->asset_maintenances_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count]));
}
if ($supplier->licenses_count > 0) {
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_licenses', ['licenses_count' => (int) $supplier->licenses_count]));
}
$supplier->delete();
return redirect()->route('suppliers.index')->with('success',
trans('admin/suppliers/message.delete.success')
);
}

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
@@ -84,10 +85,6 @@ class UsersController extends Controller
$permissions = $this->filterDisplayable($permissions);
return view('users/edit', compact('groups', 'userGroups', 'permissions', 'userPermissions'))
->with('location_list', Helper::locationsList())
->with('manager_list', Helper::managerList())
->with('company_list', Helper::companyList())
->with('department_list', Helper::departmentList())
->with('user', new User);
}
@@ -122,6 +119,11 @@ class UsersController extends Controller
$user->company_id = Company::getIdForUser($request->input('company_id', null));
$user->manager_id = $request->input('manager_id', null);
$user->notes = $request->input('notes');
$user->address = $request->input('address', null);
$user->city = $request->input('city', null);
$user->state = $request->input('state', null);
$user->country = $request->input('country', null);
$user->zip = $request->input('zip', null);
// Strip out the superuser permission if the user isn't a superadmin
$permissions_array = $request->input('permission');
@@ -231,9 +233,9 @@ class UsersController extends Controller
public function edit($id)
{
try {
$user = User::find($id);
if ($user = User::find($id)) {
$this->authorize('update', $user);
$permissions = config('permissions');
@@ -243,19 +245,14 @@ class UsersController extends Controller
$user->permissions = $user->decodePermissions();
$userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions);
$permissions = $this->filterDisplayable($permissions);
} catch (UserNotFoundException $e) {
$error = trans('admin/users/message.user_not_found', compact('id'));
return redirect()->route('users.index')->with('error', $error);
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user);
}
// Show the page
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))
->with('location_list', Helper::locationsList())
->with('department_list', Helper::departmentList())
->with('company_list', Helper::companyList())
->with('manager_list', Helper::managerList());
$error = trans('admin/users/message.user_not_found', compact('id'));
return redirect()->route('users.index')->with('error', $error);
}
/**
@@ -320,15 +317,24 @@ class UsersController extends Controller
$user->locale = $request->input('locale');
$user->employee_num = $request->input('employee_num');
$user->activated = $request->input('activated', $user->activated);
$user->jobtitle = $request->input('jobtitle');
$user->jobtitle = $request->input('jobtitle', null);
$user->phone = $request->input('phone');
$user->location_id = $request->input('location_id', null);
$user->company_id = Company::getIdForUser($request->input('company_id', null));
$user->manager_id = $request->input('manager_id', null);
$user->notes = $request->input('notes');
$user->department_id = $request->input('department_id', null);
$user->address = $request->input('address', null);
$user->city = $request->input('city', null);
$user->state = $request->input('state', null);
$user->country = $request->input('country', null);
$user->zip = $request->input('zip', null);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
// Do we want to update the user password?
if ($request->has('password')) {
$user->password = bcrypt($request->input('password'));
@@ -434,11 +440,6 @@ class UsersController extends Controller
if ($request->input('bulk_actions')=='edit') {
return view('users/bulk-edit', compact('users'))
->with('location_list', Helper::locationsList())
->with('company_list', Helper::companyList())
->with('manager_list', Helper::managerList())
->with('manager_list', Helper::managerList())
->with('department_list', Helper::departmentList())
->with('groups', Group::pluck('name', 'id'));
}
@@ -724,7 +725,7 @@ class UsersController extends Controller
$user->first_name = '';
$user->last_name = '';
$user->email = substr($user->email, ($pos = strpos($user->email, '@')) !== false ? $pos : 0);
;
$user->id = null;
// Get this user groups
@@ -737,10 +738,6 @@ class UsersController extends Controller
// Show the page
return view('users/edit', compact('permissions', 'userPermissions'))
->with('location_list', Helper::locationsList())
->with('company_list', Helper::companyList())
->with('manager_list', Helper::managerList())
->with('department_list', Helper::departmentList())
->with('user', $user)
->with('groups', Group::pluck('name', 'id'))
->with('userGroups', $userGroups)
@@ -1029,128 +1026,20 @@ 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);
}

View File

@@ -68,17 +68,12 @@ class ViewAssetsController extends Controller
public function getRequestableIndex()
{
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo', 'requests')->Hardware()->RequestableAssets()->get();
$assets = Asset::with('model', 'defaultLoc', 'location', 'assignedTo', 'requests')->Hardware()->RequestableAssets()->get();
$models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
return view('account/requestable-assets', compact('user', 'assets', 'models'));
}
public function getRequestedIndex()
{
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->get();
return view('admin/requested-assets', compact('requestedItems'));
}
public function getRequestItem($itemType, $itemId = null)

View File

@@ -25,7 +25,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\CheckForSetup::class,
\Fideloper\Proxy\TrustProxies::class,
\App\Http\Middleware\CheckForDebug::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**

View File

@@ -23,10 +23,13 @@ class AssetCheckoutRequest extends Request
*/
public function rules()
{
return [
$rules = [
"assigned_user" => 'required_without_all:assigned_asset,assigned_location',
"assigned_asset" => 'required_without_all:assigned_user,assigned_location',
"assigned_asset" => 'required_without_all:assigned_user,assigned_location|different:'.$this->id,
"assigned_location" => 'required_without_all:assigned_user,assigned_asset',
];
return $rules;
}
}

View File

@@ -30,12 +30,13 @@ class SaveUserRequest extends Request
switch($this->method())
{
// Brand new asset
// Brand new user
case 'POST':
{
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
break;
}
// Save all fields
@@ -43,11 +44,13 @@ class SaveUserRequest extends Request
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
break;
// Save only what's passed
case 'PATCH':
{
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
break;
}
default:break;

View File

@@ -25,6 +25,7 @@ class AccessoriesTransformer
'name' => e($accessory->name),
'company' => ($accessory->company) ? ['id' => $accessory->company->id,'name'=> e($accessory->company->name)] : null,
'manufacturer' => ($accessory->manufacturer) ? ['id' => $accessory->manufacturer->id,'name'=> e($accessory->manufacturer->name)] : null,
'supplier' => ($accessory->supplier) ? ['id' => $accessory->supplier->id,'name'=> e($accessory->supplier->name)] : null,
'model_number' => ($accessory->model_number) ? e($accessory->model_number) : null,
'category' => ($accessory->category) ? ['id' => $accessory->category->id,'name'=> e($accessory->category->name)] : null,
'location' => ($accessory->location) ? ['id' => $accessory->location->id,'name'=> e($accessory->location->name)] : null,
@@ -35,6 +36,7 @@ class AccessoriesTransformer
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => $accessory->numRemaining(),
'image' => ($accessory->image) ? url('/').'/uploads/accessories/'.e($accessory->image) : null,
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
@@ -59,14 +61,12 @@ class AccessoriesTransformer
}
public function transformCheckedoutAccessory (Accessory $accessory, $total)
public function transformCheckedoutAccessory ($accessory_users, $total)
{
$array = array();
foreach ($accessory->users as $user) {
foreach ($accessory_users as $user) {
$array[] = [
'assigned_pivot_id' => $user->pivot->id,
'id' => (int) $user->id,
@@ -81,8 +81,6 @@ class AccessoriesTransformer
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}

View File

@@ -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;

View File

@@ -30,7 +30,7 @@ class AssetsTransformer
'id' => (int) $asset->model->id,
'name'=> e($asset->model->name)
] : null,
'model_number' => ($asset->model) ? e($asset->model->model_number) : null,
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->present()->statusText),
@@ -48,15 +48,15 @@ class AssetsTransformer
'id' => (int) $asset->supplier->id,
'name'=> e($asset->supplier->name)
] : null,
'notes' => e($asset->notes),
'order_number' => e($asset->order_number),
'notes' => ($asset->notes) ? e($asset->notes) : null,
'order_number' => ($asset->order_number) ? e($asset->order_number) : null,
'company' => ($asset->company) ? [
'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->location) ? [
'id' => (int) $asset->location->id,
'name'=> e($asset->location->name)
] : null,
'rtd_location' => ($asset->defaultLoc) ? [
'id' => (int) $asset->defaultLoc->id,
@@ -64,10 +64,11 @@ class AssetsTransformer
] : null,
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
'assigned_to' => $this->transformAssignedTo($asset),
'warranty' => ($asset->warranty_months > 0) ? e($asset->warranty_months . ' ' . trans('admin/hardware/form.months')) : null,
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months . ' ' . trans('admin/hardware/form.months')) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($asset->updated_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'),
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
@@ -129,19 +130,19 @@ class AssetsTransformer
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),
return $asset->assigned ? [
'id' => (int) $asset->assigned->id,
'username' => e($asset->assigned->username),
'name' => e($asset->assigned->getFullNameAttribute()),
'first_name'=> e($asset->assigned->first_name),
'last_name'=> ($asset->assigned->last_name) ? e($asset->assigned->last_name) : null,
'employee_number' => ($asset->assigned->employee_num) ? e($asset->assigned->employee_num) : null,
'type' => 'user'
] : null;
}
return $asset->assignedTo ? [
'id' => $asset->assignedTo->id,
'name' => $asset->assignedTo->display_name,
return $asset->assigned ? [
'id' => $asset->assigned->id,
'name' => $asset->assigned->display_name,
'type' => $asset->assignedType()
] : null;
}

View File

@@ -25,8 +25,9 @@ class CategoriesTransformer
$array = [
'id' => (int) $category->id,
'name' => e($category->name),
'image' => ($category->image) ? e(url('/').'/uploads/categories/'.e($category->image)) : null,
'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,
@@ -39,7 +40,7 @@ class CategoriesTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Category::class) ? true : false,
'delete' => Gate::allows('delete', Category::class) ? true : false,
'delete' => (Gate::allows('delete', Category::class) && ($category->assets_count == 0) && ($category->accessories_count == 0) && ($category->consumables_count == 0) && ($category->components_count == 0)) ? true : false,
];
$array += $permissions_array;

View File

@@ -25,6 +25,7 @@ class CompaniesTransformer
$array = [
'id' => (int) $company->id,
'name' => e($company->name),
'image' => ($company->image) ? e(url('/').'/uploads/companies/'.e($company->image)) : null,
"created_at" => Helper::getFormattedDateObject($company->created_at, 'datetime'),
"updated_at" => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
"assets_count" => (int) $company->assets_count,

View File

@@ -22,7 +22,8 @@ class ComponentsTransformer
$array = [
'id' => (int) $component->id,
'name' => e($component->name),
'serial_number' => e($component->serial),
'image' => ($component->image) ? e(url('/').'/uploads/components/'.e($component->image)) : null,
'serial_number' => ($component->serial) ? e($component->serial) : null,
'location' => ($component->location) ? [
'id' => (int) $component->location->id,
'name' => e($component->location->name)
@@ -58,12 +59,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);
}
}

View File

@@ -22,6 +22,8 @@ class ConsumablesTransformer
{
$array = [
'id' => (int) $consumable->id,
'name' => e($consumable->name),
'image' => ($consumable->image) ? e(url('/').'/uploads/consumables/'.e($consumable->image)) : null,
'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null,
'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null,
'item_no' => e($consumable->item_no),
@@ -29,7 +31,6 @@ class ConsumablesTransformer
'manufacturer' => ($consumable->manufacturer) ? ['id' => (int) $consumable->manufacturer->id, 'name' => e($consumable->manufacturer->name)] : null,
'min_amt' => (int) $consumable->min_amt,
'model_number' => e($consumable->model_number),
'name' => e($consumable->name),
'remaining' => $consumable->numRemaining(),
'order_number' => e($consumable->order_number),
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),

View File

@@ -25,6 +25,7 @@ class DepartmentsTransformer
$array = [
'id' => (int) $department->id,
'name' => e($department->name),
'image' => ($department->image) ? e(url('/').'/uploads/departments/'.e($department->image)) : null,
'company' => ($department->company) ? [
'id' => (int) $department->company->id,
'name'=> e($department->company->name)

View File

@@ -33,13 +33,15 @@ class LocationsTransformer
$array = [
'id' => (int) $location->id,
'name' => e($location->name),
'image' => ($location->image) ? e(url('/').'/uploads/locations/'.e($location->image)) : null,
'address' => e($location->address),
'city' => e($location->city),
'state' => e($location->state),
'country' => e($location->country),
'zip' => e($location->zip),
'assets_checkedout' => $location->location_assets_count,
'assets_default' => $location->assigned_assets_count,
'assets_count' => (int) $location->assets_count,
'rtd_assets_count' => (int) $location->rtd_assets_count,
'users_count' => (int) $location->users_count,
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),

View File

@@ -26,6 +26,7 @@ class ManufacturersTransformer
'id' => (int) $manufacturer->id,
'name' => e($manufacturer->name),
'url' => e($manufacturer->url),
'image' => ($manufacturer->image) ? e(url('/').'/uploads/manufacturers/'.e($manufacturer->image)) : null,
'support_url' => e($manufacturer->support_url),
'support_phone' => e($manufacturer->support_phone),
'support_email' => e($manufacturer->support_email),

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Http\Transformers;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* Class SelectlistTransformer
*
* This handles the standardized formatting of the API response we need to provide for
* the rich (text and images) Select2 javascript.
*
* @package App\Http\Transformers
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0.16]
* @return \Illuminate\Http\Response
*/
class SelectlistTransformer
{
public function transformSelectlist (LengthAwarePaginator $select_items)
{
$items_array = [];
// Loop through the paginated collection to set the array values
foreach ($select_items as $select_item) {
$items_array[]= [
'id' => (int) $select_item->id,
'text' => ($select_item->use_text) ? e($select_item->use_text) : e($select_item->name),
'image' => ($select_item->use_image) ? e($select_item->use_image) : null,
];
}
$results = [
'items' => $items_array,
'pagination' =>
[
'more' => ($select_items->currentPage() >= $select_items->lastPage()) ? false : true,
'per_page' => $select_items->perPage()
],
'total_count' => $select_items->total(),
'page' => $select_items->currentPage(),
'page_count' => $select_items->lastPage()
];
return $results;
}
}

View File

@@ -26,6 +26,7 @@ class StatuslabelsTransformer
'type' => $statuslabel->getStatuslabelType(),
'color' => ($statuslabel->color) ? e($statuslabel->color) : null,
'show_in_nav' => ($statuslabel->show_in_nav=='1') ? true : false,
'assets_count' => (int) $statuslabel->assets_count,
'notes' => e($statuslabel->notes),
'created_at' => Helper::getFormattedDateObject($statuslabel->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($statuslabel->updated_at, 'datetime'),
@@ -33,7 +34,7 @@ class StatuslabelsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Statuslabel::class) ? true : false,
'delete' => Gate::allows('delete', Statuslabel::class) ? true : false,
'delete' => (Gate::allows('delete', Statuslabel::class) && ($statuslabel->assets_count == 0)) ? true : false,
];
$array += $permissions_array;

View File

@@ -25,6 +25,7 @@ class SuppliersTransformer
$array = [
'id' => (int) $supplier->id,
'name' => e($supplier->name),
'image' => ($supplier->image) ? e(url('/').'/uploads/suppliers/'.e($supplier->image)) : null,
'address' => ($supplier->address) ? e($supplier->address) : null,
'address2' => ($supplier->address2) ? e($supplier->address2) : null,
'city' => ($supplier->city) ? e($supplier->city) : null,
@@ -36,8 +37,8 @@ class SuppliersTransformer
'email' => ($supplier->email) ? e($supplier->email) : null,
'contact' => ($supplier->contact) ? e($supplier->contact) : null,
'assets_count' => (int) $supplier->assets_count,
'accessories_count' => (int) $supplier->accessories_count,
'licenses_count' => (int) $supplier->licenses_count,
'image' => ($supplier->image) ? e($supplier->image) : null,
'notes' => ($supplier->notes) ? e($supplier->notes) : null,
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'),
@@ -46,7 +47,7 @@ class SuppliersTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Supplier::class) ? true : false,
'delete' => Gate::allows('delete', Supplier::class) ? true : false,
'delete' => (Gate::allows('delete', Supplier::class) && ($supplier->assets_count == 0) && ($supplier->licenses_count == 0) && ($supplier->accessories_count == 0)) ? true : false,
];
$array += $permissions_array;

View File

@@ -23,6 +23,7 @@ class UsersTransformer
{
$array = [
'id' => (int) $user->id,
'avatar' => e($user->present()->gravatar),
'name' => e($user->first_name).' '.($user->last_name),
'firstname' => e($user->first_name),
'lastname' => e($user->last_name),
@@ -33,6 +34,12 @@ class UsersTransformer
'name'=> e($user->manager->username)
] : null,
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
'phone' => ($user->phone) ? e($user->phone) : null,
'address' => ($user->address) ? e($user->address) : null,
'city' => ($user->city) ? e($user->city) : null,
'state' => ($user->state) ? e($user->state) : null,
'country' => ($user->country) ? e($user->country) : null,
'zip' => ($user->zip) ? e($user->zip) : null,
'email' => e($user->email),
'department' => ($user->department) ? [
'id' => (int) $user->department->id,
@@ -42,6 +49,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,
@@ -57,7 +65,7 @@ class UsersTransformer
$permissions_array['available_actions'] = [
'update' => (Gate::allows('update', User::class) && ($user->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', User::class) && ($user->deleted_at=='')) ? true : false,
'delete' => (Gate::allows('delete', User::class) && ($user->deleted_at=='') && ($user->assets_count == 0) && ($user->licenses_count == 0) && ($user->accessories_count == 0) && ($user->consumables_count == 0)) ? true : false,
'clone' => (Gate::allows('create', User::class) && ($user->deleted_at=='')) ,
'restore' => (Gate::allows('create', User::class) && ($user->deleted_at!='')) ? true : false,
];

View File

@@ -23,14 +23,20 @@ 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);
} else {
$this->item['custom_fields'][$customField->db_column_name()] = '';
}
}
}
$this->createAssetIfNotExists($row);
}
@@ -61,7 +67,7 @@ class AssetImporter extends ItemImporter
}
$this->item['image'] = $this->findCsvMatch($row, "image");
$this->item['warranty_months'] = intval($this->findCsvMatch($row, "warranty"));
$this->item['warranty_months'] = intval($this->findCsvMatch($row, "warranty_months"));
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
// If no status ID is found

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;
}

View File

@@ -17,7 +17,7 @@ class Accessory extends SnipeModel
use Loggable, Presentable;
use SoftDeletes;
protected $dates = ['deleted_at', 'purchase_date'];
protected $dates = ['deleted_at'];
protected $table = 'accessories';
protected $casts = [
'requestable' => 'boolean'
@@ -61,10 +61,19 @@ class Accessory extends SnipeModel
'purchase_date',
'model_number',
'manufacturer_id',
'supplier_id',
'image',
'qty',
'requestable'
];
public function supplier()
{
return $this->belongsTo('\App\Models\Supplier', 'supplier_id');
}
public function setRequestableAttribute($value)
{
if ($value == '') {

View File

@@ -21,8 +21,7 @@ use Illuminate\Notifications\Notifiable;
class Asset extends Depreciable
{
protected $presenter = 'App\Presenters\AssetPresenter';
use Loggable, Requestable, Presentable, Notifiable;
use SoftDeletes;
use Loggable, Requestable, Presentable, Notifiable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait;
const LOCATION = 'location';
const ASSET = 'asset';
@@ -53,7 +52,6 @@ class Asset extends Depreciable
];
use ValidatingTrait, UniqueUndeletedTrait;
protected $rules = [
'name' => 'max:255|nullable',
@@ -85,6 +83,7 @@ class Asset extends Depreciable
'model_id',
'name',
'notes',
'order_number',
'purchase_cost',
'purchase_date',
'rtd_location_id',
@@ -94,6 +93,8 @@ class Asset extends Depreciable
'warranty_months',
];
public function getDisplayNameAttribute()
{
return $this->present()->name();
@@ -126,11 +127,10 @@ class Asset extends Depreciable
public function availableForCheckout()
{
return (
empty($this->assigned_to) &&
$this->assetstatus->deployable == 1 &&
empty($this->deleted_at)
);
if ((empty($this->assigned_to)) && (empty($this->deleted_at)) && ($this->assetstatus->deployable == 1)) {
return true;
}
return false;
}
/**
@@ -184,7 +184,7 @@ class Asset extends Depreciable
} else {
$user_name = "Unassigned";
}
return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . $this->model->name;
return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . ($this->model) ? $this->model->name: '';
}
public function validationRules($id = '0')
@@ -254,23 +254,39 @@ class Asset extends Depreciable
**/
public function assetLoc()
{
static $iterations=0;
static $first_asset;
if (!empty($this->assignedType())) {
// dd($this->assignedType());
if ($this->assignedType() == self::ASSET) {
return $this->assignedto->assetloc(); // Recurse until we have a final location
$iterations++;
if(!$first_asset) {
$first_asset=$this;
}
if($iterations>10) {
throw new \Exception("Asset assignment Loop for Asset ID: ".$first_asset->id);
}
$assigned_to=Asset::find($this->assigned_to); //have to do this this way because otherwise it errors
if ($assigned_to) {
return $assigned_to->assetLoc();
} // Recurse until we have a final location
}
if ($this->assignedType() == self::LOCATION) {
return $this->assignedTo();
if ($this->assignedTo) {
return $this->assignedTo;
}
}
if ($this->assignedType() == self::USER) {
if (!$this->assignedTo) {
return $this->defaultLoc();
if (($this->assignedTo) && $this->assignedTo->userLoc) {
return $this->assignedTo->userLoc;
}
return $this->assignedTo->userLoc();
//this makes no sense
return $this->defaultLoc;
}
}
return $this->defaultLoc();
return $this->defaultLoc;
}
public function assignedType()
@@ -406,6 +422,12 @@ class Asset extends Depreciable
}
public function location()
{
return $this->belongsTo('\App\Models\Location', 'location_id');
}
/**
* Get auto-increment
@@ -487,7 +509,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;
}
}
@@ -781,14 +803,11 @@ class Asset extends Depreciable
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assignedTo', 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.'%')
@@ -815,57 +834,60 @@ class Asset extends Depreciable
{
return $query->where(function ($query) use ($filter) {
foreach ($filter as $key => $search_val) {
if ($key =='asset_tag') {
$fieldname = str_replace('custom_fields.','', $key) ;
if ($fieldname =='asset_tag') {
$query->where('assets.asset_tag', 'LIKE', '%'.$search_val.'%');
}
if ($key =='name') {
if ($fieldname =='name') {
$query->where('assets.name', 'LIKE', '%'.$search_val.'%');
}
if ($key =='product_key') {
if ($fieldname =='product_key') {
$query->where('assets.serial', 'LIKE', '%'.$search_val.'%');
}
if ($key =='purchase_date') {
if ($fieldname =='purchase_date') {
$query->where('assets.purchase_date', 'LIKE', '%'.$search_val.'%');
}
if ($key =='purchase_cost') {
if ($fieldname =='purchase_cost') {
$query->where('assets.purchase_cost', 'LIKE', '%'.$search_val.'%');
}
if ($key =='notes') {
if ($fieldname =='notes') {
$query->where('assets.notes', 'LIKE', '%'.$search_val.'%');
}
if ($key =='order_number') {
if ($fieldname =='order_number') {
$query->where('assets.order_number', 'LIKE', '%'.$search_val.'%');
}
if ($key =='status_label') {
if ($fieldname =='status_label') {
$query->whereHas('assetstatus', function ($query) use ($search_val) {
$query->where('status_labels.name', 'LIKE', '%' . $search_val . '%');
});
}
if ($key =='location') {
if ($fieldname =='location') {
$query->whereHas('defaultLoc', function ($query) use ($search_val) {
$query->where('locations.name', 'LIKE', '%' . $search_val . '%');
});
}
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 . '%');
if ($fieldname =='checkedout_to') {
$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 . '%');
});
});
}
if ($key =='manufacturer') {
if ($fieldname =='manufacturer') {
$query->whereHas('model', function ($query) use ($search_val) {
$query->whereHas('manufacturer', function ($query) use ($search_val) {
$query->where(function ($query) use ($search_val) {
@@ -875,9 +897,9 @@ class Asset extends Depreciable
});
}
if ($key =='category') {
$query->whereHas('model', function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
if ($fieldname =='category') {
$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 . '%')
@@ -887,7 +909,7 @@ class Asset extends Depreciable
});
}
if ($key =='model') {
if ($fieldname =='model') {
$query->where(function ($query) use ($search_val) {
$query->whereHas('model', function ($query) use ($search_val) {
$query->where('models.name', 'LIKE', '%' . $search_val . '%');
@@ -895,7 +917,7 @@ class Asset extends Depreciable
});
}
if ($key =='model_number') {
if ($fieldname =='model_number') {
$query->where(function ($query) use ($search_val) {
$query->whereHas('model', function ($query) use ($search_val) {
$query->where('models.model_number', 'LIKE', '%' . $search_val . '%');
@@ -904,7 +926,7 @@ class Asset extends Depreciable
}
if ($key =='company') {
if ($fieldname =='company') {
$query->where(function ($query) use ($search_val) {
$query->whereHas('company', function ($query) use ($search_val) {
$query->where('companies.name', 'LIKE', '%' . $search_val . '%');
@@ -913,12 +935,12 @@ 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%");
}
}
$query->orWhere('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%');
});
}
@@ -1060,7 +1082,7 @@ class Asset extends Depreciable
*/
public function scopeOrderLocation($query, $order)
{
return $query->join('locations', 'locations.id', '=', 'assets.rtd_location_id')->orderBy('locations.name', $order);
return $query->leftJoin('locations', 'locations.id', '=', 'assets.rtd_location_id')->orderBy('locations.name', $order);
}
@@ -1103,4 +1125,20 @@ class Asset extends Depreciable
}
/**
* 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);
}
}

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'
];

View File

@@ -149,21 +149,21 @@ class AssetModel extends SnipeModel
public function scopeTextSearch($query, $search)
{
return $query->where('name', 'LIKE', "%$search%")
return $query->where('models.name', 'LIKE', "%$search%")
->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.'%');
});
});

View File

@@ -37,12 +37,6 @@ class CheckoutRequest extends Model
public function location()
{
if ($this->itemType() == "asset") {
$asset = $this->itemRequested();
if ($asset->assignedTo) {
return $asset->assetloc;
}
}
return $this->itemRequested()->location;
}

View File

@@ -192,4 +192,20 @@ final class Company extends SnipeModel
{
return $this->hasMany(Component::class);
}
/**
* 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.'%');
});
}
}

View File

@@ -64,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()

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;
});

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.'%');
});
}
}

View File

@@ -77,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;

View File

@@ -54,12 +54,23 @@ class Location extends SnipeModel
public function assets()
{
return $this->hasManyThrough('\App\Models\Asset', '\App\Models\User', 'location_id', 'assigned_to', 'id');
return $this->hasMany('\App\Models\Asset', 'location_id');
}
public function locationAssets()
public function rtd_assets()
{
return $this->hasMany('\App\Models\Asset', 'rtd_location_id')->orHas('assignedAssets');
/* This used to have an ...->orHas() clause that referred to
assignedAssets, and that was probably incorrect, as well as
definitely was setting fire to the query-planner. So don't do that.
It is arguable that we should have a '...->whereNull('assigned_to')
bit in there, but that isn't always correct either (in the case
where a user has no location, for example).
In all likelyhood, we need to denorm an "effective_location" column
into Assets to make this slightly less miserable.
*/
return $this->hasMany('\App\Models\Asset', 'rtd_location_id');
}
public function parent()
@@ -77,12 +88,18 @@ class Location extends SnipeModel
return $this->hasMany('\App\Models\Location', 'parent_id');
}
// I don't think we need this anymore since we de-normed location_id in assets?
public function assignedAssets()
{
return $this->morphMany('App\Models\Asset', 'assigned', 'assigned_type', 'assigned_to')->withTrashed();
// 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)
{

View File

@@ -38,6 +38,7 @@ class Setting extends Model
"pwd_secure_min" => "numeric|required|min:5",
"audit_warning_days" => "numeric|nullable",
"audit_interval" => "numeric|nullable",
"custom_forgot_pass_url" => "url|nullable",
];
protected $fillable = ['site_name','email_domain','email_format','username_format'];

View File

@@ -29,16 +29,6 @@ class Statuslabel extends SnipeModel
protected $fillable = ['name', 'deployable', 'pending', 'archived'];
/**
* Show count of assets with status label
*
* @todo Remove this. It's dumb.
* @return \Illuminate\Support\Collection
*/
public function has_assets()
{
return $this->hasMany('\App\Models\Asset', 'status_id')->count();
}
/**
* Get assets with associated status label
@@ -59,14 +49,41 @@ class Statuslabel extends SnipeModel
return 'archived';
} elseif (($this->pending == '0') && ($this->archived == '0') && ($this->deployable == '0')) {
return 'undeployable';
} else {
return 'deployable';
}
return 'deployable';
}
public function scopePending()
{
return $this->where('pending', '=', 1)
->where('archived', '=', 0)
->where('deployable', '=', 0);
}
public function scopeArchived()
{
return $this->where('pending', '=', 0)
->where('archived', '=', 1)
->where('deployable', '=', 0);
}
public function scopeDeployable()
{
return $this->where('pending', '=', 0)
->where('archived', '=', 0)
->where('deployable', '=', 1);
}
public static function getStatuslabelTypesForDB($type)
{
$statustype['pending'] = 0;
$statustype['deployable'] = 0;
$statustype['archived'] = 0;
if ($type == 'pending') {
$statustype['pending'] = 1;
$statustype['deployable'] = 0;
@@ -81,12 +98,6 @@ class Statuslabel extends SnipeModel
$statustype['pending'] = 0;
$statustype['deployable'] = 0;
$statustype['archived'] = 1;
} else {
$statustype['pending'] = 0;
$statustype['deployable'] = 0;
$statustype['archived'] = 0;
}
return $statustype;

View File

@@ -68,6 +68,11 @@ class Supplier extends SnipeModel
return $this->hasMany('\App\Models\Asset', 'supplier_id');
}
public function accessories()
{
return $this->hasMany('\App\Models\Accessory', 'supplier_id');
}
public function asset_maintenances()
{
return $this->hasMany('\App\Models\AssetMaintenance', 'supplier_id');

View File

@@ -4,8 +4,10 @@ namespace App\Models;
use App\Presenters\Presentable;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Http\Traits\UniqueUndeletedTrait;
@@ -16,7 +18,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
{
protected $presenter = 'App\Presenters\UserPresenter';
use SoftDeletes, ValidatingTrait;
use Authenticatable, CanResetPassword, HasApiTokens;
use Authenticatable, Authorizable, CanResetPassword, HasApiTokens;
use UniqueUndeletedTrait;
use Notifiable;
use Presentable;
@@ -36,6 +38,11 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
'phone_number',
'username',
'first_name',
'address',
'city',
'state',
'country',
'zip',
];
protected $casts = [
@@ -53,7 +60,8 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
'username' => 'required|string|min:1|unique_undeleted',
'email' => 'email|nullable',
'password' => 'required|min:6',
'locale' => 'max:10|nullable'
'locale' => 'max:10|nullable',
'manager_id' => 'nullable|different:id',
];
@@ -191,12 +199,22 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
/**
* Get the asset's location based on the assigned user
* @todo - this should be removed once we're sure we've switched it
* to location()
**/
public function userloc()
{
return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed();
}
/**
* Get the asset's location based on the assigned user
**/
public function location()
{
return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed();
}
/**
* Get the user's manager based on the assigned user
**/
@@ -378,6 +396,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('groups.id', '=', $id);
});
}
/**
* Query builder scope to search on text
*
@@ -395,6 +421,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
->orWhere('users.email', 'LIKE', "%$search%")
->orWhere('users.username', 'LIKE', "%$search%")
->orWhere('users.notes', 'LIKE', "%$search%")
->orWhere('users.phone', 'LIKE', "%$search%")
->orWhere('users.jobtitle', 'LIKE', "%$search%")
->orWhere('users.employee_num', 'LIKE', "%$search%")
->orWhere(function ($query) use ($search) {

View File

@@ -45,13 +45,12 @@ class CheckoutNotification extends Notification
$item = $this->params['item'];
if (class_basename(get_class($this->params['item']))=='Asset') {
$notifyBy[] = 'mail';
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance() == '1'))
|| (method_exists($item, 'getEula') && ($item->getEula()))
) {
$notifyBy[] = 'mail';
}
}
// if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
// || (method_exists($item, 'getEula') && ($item->getEula()))
// ) {
// $notifyBy[] = 'mail';
// }
return $notifyBy;
}
@@ -83,6 +82,7 @@ class CheckoutNotification extends Notification
*/
public function toMail($notifiable)
{
if (class_basename(get_class($this->params['item']))=='Asset') {
//TODO: Expand for non assets.
$item = $this->params['item'];
@@ -99,11 +99,19 @@ class CheckoutNotification extends Notification
'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,
];
return (new MailMessage)
->view('emails.accept-asset', $data)
->subject(trans('mail.Confirm_asset_delivery'));
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'));
}
}

View File

@@ -2,118 +2,12 @@
namespace App\Policies;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Policies\CheckoutablePermissionsPolicy;
class AccessoryPolicy
class AccessoryPolicy extends CheckoutablePermissionsPolicy
{
use HandlesAuthorization;
public function before(User $user, $ability, $accessory)
protected function columnName()
{
// Lets move all company related checks here.
if ($accessory instanceof \App\Models\Accessory && !Company::isCurrentUserHasAccess($accessory)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
public function index(User $user)
{
// dd('here');
return $user->hasAccess('accessories.view');
}
/**
* Determine whether the user can view the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function view(User $user, Accessory $accessory = null)
{
//
return $user->hasAccess('accessories.view');
}
/**
* Determine whether the user can create accessories.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return $user->hasAccess('accessories.create');
}
/**
* Determine whether the user can update the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function update(User $user, Accessory $accessory = null)
{
//
return $user->hasAccess('accessories.edit');
}
/**
* Determine whether the user can delete the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function delete(User $user, Accessory $accessory = null)
{
//
return $user->hasAccess('accessories.delete');
}
/**
* Determine whether the user can checkout the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function checkout(User $user, Accessory $accessory = null)
{
return $user->hasAccess('accessories.checkout');
}
/**
* Determine whether the user can checkin the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function checkin(User $user, Accessory $accessory = null)
{
return $user->hasAccess('accessories.checkin');
}
/**
* Determine whether the user can manage the accessory.
*
* @param \App\User $user
* @param \App\Accessory $accessory
* @return mixed
*/
public function manage(User $user, Accessory $accessory = null)
{
return $user->hasAccess('accessories.checkin')
|| $user->hasAccess('accessories.edit')
|| $user->hasAccess('accessories.checkout');
return 'accessories';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class AssetModelPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'models';
}
}

View File

@@ -2,79 +2,18 @@
namespace App\Policies;
use App\Models\Asset;
use App\Models\Company;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Policies\CheckoutablePermissionsPolicy;
class AssetPolicy
class AssetPolicy extends CheckoutablePermissionsPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* @return void
*/
public function __construct()
protected function columnName()
{
//
}
public function before(User $user, $ability, $asset)
{
// Lets move all company related checks here.
if ($asset instanceof \App\Models\Asset && !Company::isCurrentUserHasAccess($asset)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
public function index(User $user)
{
return $user->hasAccess('assets.view');
}
public function view(User $user, Asset $asset)
{
return $user->hasAccess('assets.view');
return 'assets';
}
public function viewRequestable(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.view.requestable');
}
public function create(User $user)
{
return $user->hasAccess('assets.create');
}
public function checkout(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.checkout');
}
public function checkin(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.checkin');
}
public function delete(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.delete');
}
public function manage(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.checkin')
|| $user->hasAccess('assets.edit')
|| $user->hasAccess('assets.delete')
|| $user->hasAccess('assets.checkout');
}
public function update(User $user, Asset $asset = null)
{
return $user->hasAccess('assets.edit');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class CategoryPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'categories';
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Policies;
use App\Models\User;
use App\Policies\SnipePermissionsPolicy;
abstract class CheckoutablePermissionsPolicy extends SnipePermissionsPolicy
{
/**
* Determine whether the user can checkout the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function checkout(User $user, $item = null)
{
return $user->hasAccess($this->columnName().'.checkout');
}
/**
* Determine whether the user can checkin the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function checkin(User $user, $item = null)
{
return $user->hasAccess($this->columnName().'.checkin');
}
/**
* Determine whether the user can manage the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function manage(User $user, $item = null)
{
return $user->hasAccess($this->columnName().'.checkin')
|| $user->hasAccess($this->columnName().'.edit')
|| $user->hasAccess($this->columnName().'.checkout');
}
}

View File

@@ -2,113 +2,12 @@
namespace App\Policies;
use App\Models\Company;
use App\Models\Component;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Policies\CheckoutablePermissionsPolicy;
class ComponentPolicy
class ComponentPolicy extends CheckoutablePermissionsPolicy
{
use HandlesAuthorization;
public function before(User $user, $ability, $component)
protected function columnName()
{
// Lets move all company related checks here.
if ($component instanceof \App\Models\Component && !Company::isCurrentUserHasAccess($component)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
/**
* Determine whether the user can view the component.
*
* @param \App\User $user
* @param \App\Component $component
* @return mixed
*/
public function view(User $user, Component $component = null)
{
//
return $user->hasAccess('components.view');
}
/**
* Determine whether the user can create components.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return $user->hasAccess('components.create');
}
/**
* Determine whether the user can update the component.
*
* @param \App\User $user
* @param \App\Component $component
* @return mixed
*/
public function update(User $user, Component $component = null)
{
//
return $user->hasAccess('components.edit');
}
/**
* Determine whether the user can delete the component.
*
* @param \App\User $user
* @param \App\Component $component
* @return mixed
*/
public function delete(User $user, Component $component = null)
{
//
return $user->hasAccess('components.delete');
}
/**
* Determine whether the user can checkout the component.
*
* @param \App\User $user
* @param \App\Accessory $component
* @return mixed
*/
public function checkout(User $user, Component $component = null)
{
return $user->hasAccess('components.checkout');
}
/**
* Determine whether the user can checkin the component.
*
* @param \App\User $user
* @param \App\Component $component
* @return mixed
*/
public function checkin(User $user, Component $component = null)
{
return $user->hasAccess('components.checkin');
}
/**
* Determine whether the user can manage the component.
*
* @param \App\User $user
* @param \App\Component $component
* @return mixed
*/
public function manage(User $user, Component $component = null)
{
return $user->hasAccess('components.checkin')
|| $user->hasAccess('components.edit')
|| $user->hasAccess('components.checkout');
return 'components';
}
}

View File

@@ -2,118 +2,12 @@
namespace App\Policies;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Policies\CheckoutablePermissionsPolicy;
class ConsumablePolicy
class ConsumablePolicy extends CheckoutablePermissionsPolicy
{
use HandlesAuthorization;
public function before(User $user, $ability, $consumable)
protected function columnName()
{
// Lets move all company related checks here.
if ($consumable instanceof \App\Models\Consumable && !Company::isCurrentUserHasAccess($consumable)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
/**
* Determine whether the user can view the consumable.
*
* @param \App\User $user
* @param \App\Consumable $consumable
* @return mixed
*/
public function view(User $user, Consumable $consumable = null)
{
//
return $user->hasAccess('consumables.view');
}
/**
* Determine whether the user can create consumables.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return $user->hasAccess('consumables.create');
}
/**
* Determine whether the user can update the consumable.
*
* @param \App\User $user
* @param \App\Consumable $consumable
* @return mixed
*/
public function update(User $user, Consumable $consumable = null)
{
//
return $user->hasAccess('consumables.edit');
}
/**
* Determine whether the user can delete the consumable.
*
* @param \App\User $user
* @param \App\Consumable $consumable
* @return mixed
*/
public function delete(User $user, Consumable $consumable = null)
{
//
return $user->hasAccess('consumables.delete');
}
/**
* Determine whether the user can checkout the consumable.
*
* @param \App\User $user
* @param \App\Accessory $consumable
* @return mixed
*/
public function checkout(User $user, Consumable $consumable = null)
{
return $user->hasAccess('consumables.checkout');
}
/**
* Determine whether the user can checkin the consumable.
*
* @param \App\User $user
* @param \App\Consumable $consumable
* @return mixed
*/
public function checkin(User $user, Consumable $consumable = null)
{
return $user->hasAccess('consumables.checkin');
}
public function index(User $user)
{
return $user->hasAccess('consumables.view');
}
/**
* Determine whether the user can manage the consumable.
*
* @param \App\User $user
* @param \App\Consumable $consumable
* @return mixed
*/
public function manage(User $user, Consumable $consumable = null)
{
return $user->hasAccess('consumables.checkin')
|| $user->hasAccess('consumables.edit')
|| $user->hasAccess('consumables.checkout');
return 'consumables';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class CustomFieldPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'customfields';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class DepartmentPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'departments';
}
}

View File

@@ -2,102 +2,17 @@
namespace App\Policies;
use App\Models\Company;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Policies\CheckoutablePermissionsPolicy;
class LicensePolicy
class LicensePolicy extends CheckoutablePermissionsPolicy
{
use HandlesAuthorization;
public function before(User $user, $ability, $license)
protected function columnName()
{
// Lets move all company related checks here.
if ($license instanceof \App\Models\License && !Company::isCurrentUserHasAccess($license)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
/**
* Determine whether the user can view the license.
*
* @param \App\User $user
* @param \App\License $license
* @return mixed
*/
public function view(User $user, License $license = null)
{
//
return $user->hasAccess('licenses.view');
return 'licenses';
}
/**
* Determine whether the user can create licenses.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return $user->hasAccess('licenses.create');
}
/**
* Determine whether the user can update the license.
*
* @param \App\User $user
* @param \App\License $license
* @return mixed
*/
public function update(User $user, License $license = null)
{
//
return $user->hasAccess('licenses.edit');
}
/**
* Determine whether the user can delete the license.
*
* @param \App\User $user
* @param \App\License $license
* @return mixed
*/
public function delete(User $user, License $license = null)
{
//
return $user->hasAccess('licenses.delete');
}
/**
* Determine whether the user can checkout the license.
*
* @param \App\User $user
* @param \App\Accessory $license
* @return mixed
*/
public function checkout(User $user, LicenseSeat $license = null)
{
return $user->hasAccess('licenses.checkout');
}
/**
* Determine whether the user can checkin the license.
*
* @param \App\User $user
* @param \App\License $license
* @return mixed
*/
public function checkin(User $user, LicenseSeat $license = null)
{
return $user->hasAccess('licenses.checkin');
}
/**
* Determine whether the user can view license keys
*
@@ -110,18 +25,4 @@ class LicensePolicy
return $user->hasAccess('licenses.keys');
}
/**
* Determine whether the user can manage the license.
*
* @param \App\User $user
* @param \App\License $license
* @return mixed
*/
public function manage(User $user, License $license = null)
{
return $user->hasAccess('licenses.checkin')
|| $user->hasAccess('licenses.edit')
|| $user->hasAccess('licenses.delete')
|| $user->hasAccess('licenses.checkout');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class LocationPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'locations';
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace App\Policies;
use App\Models\Company;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
abstract class SnipePermissionsPolicy
{
// This should return the key of the model in the users json permission string.
abstract protected function columnName();
use HandlesAuthorization;
public function before(User $user, $ability, $item)
{
// Lets move all company related checks here.
if ($item instanceof \App\Models\SnipeModel && !Company::isCurrentUserHasAccess($item)) {
return false;
}
// If an admin, they can do all asset related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
public function index(User $user)
{
// dd('here');
return $user->hasAccess($this->columnName().'.view');
}
/**
* Determine whether the user can view the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function view(User $user, $item = null)
{
//
return $user->hasAccess($this->columnName().'.view');
}
/**
* Determine whether the user can create accessories.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
return $user->hasAccess($this->columnName().'.create');
}
/**
* Determine whether the user can update the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function update(User $user, $item = null)
{
//
return $user->hasAccess($this->columnName().'.edit');
}
/**
* Determine whether the user can delete the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function delete(User $user, $item = null)
{
//
return $user->hasAccess($this->columnName().'.delete');
}
/**
* Determine whether the user can manage the accessory.
*
* @param \App\User $user
* @return mixed
*/
public function manage(User $user, $item = null)
{
return $user->hasAccess($this->columnName().'.edit');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class StatuslabelPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'statuslabels';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Policies;
use App\Policies\SnipePermissionsPolicy;
class SupplierPolicy extends SnipePermissionsPolicy
{
protected function columnName()
{
return 'suppliers';
}
}

View File

@@ -2,87 +2,12 @@
namespace App\Policies;
use App\Models\Company;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Support\Facades\Auth;
use App\Policies\SnipePermissionsPolicy;
class UserPolicy
class UserPolicy extends SnipePermissionsPolicy
{
use HandlesAuthorization;
public function before(User $user, $ability, $targetUser)
protected function columnName()
{
// Lets move all company related checks here.
if ($targetUser instanceof \App\Models\User && !Company::isCurrentUserHasAccess($targetUser)) {
return false;
}
// If an admin, they can do all user related tasks.
if ($user->hasAccess('admin')) {
return true;
}
}
/**
* Determine whether the user can view the targetUser.
*
* @param \App\Models\User $user
* @param \App\Models\Consumable $targetUser
* @return mixed
*/
public function view(User $user, User $targetUser = null)
{
//
return $user->hasAccess('users.view');
}
/**
* Determine whether the user can create users.
*
* @param \App\Models\User $user
* @return mixed
*/
public function create(User $user)
{
return $user->hasAccess('users.create');
}
/**
* Determine whether the user can update the targetUser.
*
* @param \App\Models\User $user
* @param \App\Models\User $targetUser
* @return mixed
*/
public function update(User $user, User $targetUser = null)
{
return $user->hasAccess('users.edit');
}
/**
* Determine whether the user can delete the targetUser.
*
* @param \App\Models\User $user
* @param \App\Models\User $targetUser
* @return mixed
*/
public function delete(User $user, User $targetUser = null)
{
if ($targetUser) {
//We can't delete ourselves.
if ($user->id == $targetUser->id) {
return false;
}
if ((!Auth::user()->isSuperUser()) || (config('app.lock_passwords'))) {
return false;
}
}
return $user->hasAccess('users.delete');
}
public function index(User $user)
{
return $user->hasAccess('users.view');
return 'users';
}
}

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