Compare commits

..

568 Commits

Author SHA1 Message Date
snipe 5266bd4415 Bumped version 2016-07-19 02:04:08 -07:00
snipe ebc74a6530 [Security] Updating Guzzle to address CVE-2016-5385 2016-07-19 00:36:50 -07:00
snipe 13d250f095 Merge branch 'v3' of github.com:snipe/snipe-it into v3
# Conflicts:
#	app/Models/Ldap.php
2016-07-19 00:13:01 -07:00
Daniel Meltzer 68d8e6a3a9 Importer again (#2260)
* Quote item names when displaying in error table.

* Remove the danger class as well as the warning class when uploading a file.  Fixes a display error if a file is successful after a file fails upload.
2016-07-18 15:46:03 -07:00
snipe 192b1582f5 Merge branch 'v3' of git@github.com:snipe/snipe-it.git 2016-07-15 16:46:15 -07:00
snipe 27b8d326e3 fix for undefined user 2016-07-15 16:38:49 -07:00
snipe 7e56934484 Removed leftover user code 2016-07-15 14:58:29 -07:00
snipe 698cb161d4 Not sure how this ever worked? 2016-07-15 11:11:48 -07:00
snipe 92175eb700 Few more LDAP/AD tweaks 2016-07-14 23:49:32 -07:00
snipe 616f922306 Fixes #2254 2016-07-14 19:50:00 -07:00
snipe c1d2be651a Removed default pemissions 2016-07-14 18:32:54 -07:00
snipe 8729871353 Fucking rookie mistake. Send redbull. 2016-07-14 16:52:20 -07:00
snipe 99a42dfc38 More AD fixes 2016-07-14 16:27:32 -07:00
snipe 0cf8ac1d95 Add AD domain to settings 2016-07-14 15:52:52 -07:00
snipe 8fd8e747d9 Fix for missing input variable in suppliers ajax method 2016-07-13 22:35:21 -07:00
snipe e6b872299d Possible fix for #2246 - needs AD testing 2016-07-13 15:18:29 -07:00
snipe a00198abc7 Added spinner for LDAP test 2016-07-13 07:34:54 -07:00
snipe 40b56cfad7 Removed unused variables 2016-07-13 07:24:54 -07:00
snipe 5cd2c78d5e Link to location view, not edit 2016-07-13 07:16:10 -07:00
snipe 2ce1d8b985 Fixed missing use statement 2016-07-13 07:13:49 -07:00
snipe f3e99113d2 Bumped version 2016-07-13 05:53:23 -07:00
snipe ab6e2a7301 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-07-13 05:50:45 -07:00
snipe e7038cfdc8 LDAP tester 2016-07-13 05:50:40 -07:00
snipe 4233c781ac Reworked LDAP login. Fixes #2218
LDAP no longer fails completely when the connection settings are wrong, or when app key is messed up. Rather than auth as the admin user and search, we auth as the user themselves. Admin auth is only for LDAP sync now.

This should mean much fewer problems with donked LDAP settings and login.
2016-07-13 05:50:24 -07:00
snipe b5d3843b7c New LDAP model 2016-07-13 05:48:16 -07:00
snipe 026f099ba3 Fixed indenting 2016-07-13 05:47:32 -07:00
snipe ff6c3cfa17 Added LDAP settings check in settings page 2016-07-13 05:47:23 -07:00
Daniel Meltzer bf88cd8233 Check for variables to exist and not null rather than assuming it does. Fixes #2247. (#2248) 2016-07-12 21:03:23 -07:00
snipe c8351ae01b Reverting back to or die 2016-07-11 18:25:29 -07:00
snipe 7a4cbce460 Use trans instead of lang:: 2016-07-10 21:07:59 -07:00
snipe 3f835ba847 Updated lang to trans 2016-07-10 21:04:49 -07:00
snipe f87fbbdb1d Removed unused use statement 2016-07-10 21:01:11 -07:00
snipe caee42e843 More valid composer name 2016-07-10 20:57:12 -07:00
snipe 4e38f96f97 Switched or and and to || and && for code quality 2016-07-10 20:55:44 -07:00
snipe 814f8ea5fb Added favicon 2016-07-10 18:53:25 -07:00
Daniel Meltzer ab3b9dcf5d Add a clone button the the user table. (#2241)
Also preserve permissions when cloning a user, instead of nulling them by default.
2016-07-10 18:43:10 -07:00
Daniel Meltzer f683c78a69 Fix adding an image to an asset when public/uploads/assets does not exist (#2240)
* Fix adding an image to an asset when public/uploads/assets does not exist.

 First check to see if we can create directory and do so.  If any errors occur, display the error string as an error on the page.

* Add the public/uploads/assets directory to new installs.

* Add some comments explaining this code so I remember what it does next time.
2016-07-10 18:43:00 -07:00
snipe 642be61007 Remove old asset importer 2016-07-09 19:35:42 -07:00
snipe 8d71e6b268 Fixed indenting 2016-07-09 18:20:57 -07:00
snipe 6bdc88cfea Removed extra space 2016-07-09 18:20:14 -07:00
snipe 7ff77981f6 Fixed indenting 2016-07-09 18:19:51 -07:00
snipe a9f060e768 Removed extraneous comments 2016-07-09 18:19:19 -07:00
snipe 6de943b226 Use latest spatie/laravel-backup 2016-07-07 05:04:45 -07:00
snipe 262fe62409 Updated composer lock 2016-07-07 04:51:58 -07:00
snipe 9f4e0491ed Fixes error in license checkout 2016-07-07 04:13:08 -07:00
snipe 7ee135826f Updated composer with more accurate info 2016-07-07 02:07:42 -07:00
snipe 5e8d8d6df0 Nicer date display 2016-07-07 02:07:31 -07:00
snipe f2ddc7b0ae Added purchase cost and purchase date to listing 2016-07-07 02:07:21 -07:00
snipe 01b01c6479 Fixes #2149 2016-07-07 01:13:31 -07:00
snipe 3bb5479efd Move print statement to LOG 2016-07-01 16:24:58 -07:00
snipe 85606d830d Merge remote-tracking branch 'origin/v3' into v3-master 2016-07-01 01:06:41 -07:00
snipe 8fe1b88947 Disable email alerts on backups by default 2016-07-01 01:05:45 -07:00
snipe 9144605b57 Updated php codesniffer 2016-07-01 01:05:32 -07:00
snipe a7a748385f Longer cookie 2016-07-01 01:05:22 -07:00
snipe d4628b5c0f Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-29 04:31:42 -07:00
snipe 0c65b6cad1 Nicer bulk delete layout 2016-06-29 04:30:21 -07:00
snipe 0c98390eef Hide bulk actions, checkbox and checkout/in if deleted 2016-06-29 04:19:37 -07:00
Brady Wetherington 345a0da337 Add Unix Socket support to standard .env configurations for DB (#2208) 2016-06-28 20:15:03 -07:00
snipe 38a7bfecf6 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-28 14:52:58 -07:00
snipe 6d5bc64b2b Another fix for status label types
This is a little janky, as it breaks up the errors into multiple screens if you don't have a status label type AND don't have a name. This is because the model-level validation won't work since we transmogrify that dropdown list of status label types into  boolean values for the DB. Should eventually find a less clunky way to handle this, but needed to get a fix in now.
2016-06-28 14:52:11 -07:00
snipe 7c4b2caadf Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-28 12:40:31 -07:00
snipe 6633366b29 Small fix for status label types 2016-06-28 12:40:20 -07:00
snipe 64dbcf7c92 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-28 12:19:36 -07:00
snipe 483bf1b309 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-06-28 12:19:19 -07:00
snipe 0e96a0aa3e Updated comment 2016-06-28 12:19:14 -07:00
snipe e4275bd3d3 Fixes status label inline creation 2016-06-28 12:19:05 -07:00
Daniel Meltzer 52c89ca889 Hide Delete action if user is deleted. (#2205)
Issue: 1493
2016-06-28 11:50:11 -07:00
Daniel Meltzer d484636bba Add model number column to the hardware list. (#2204)
* Add model number column to the hardware list and allow searching based on model number.   Column is hidden by default.

* Fix sorting.  Add scope to order by model number.
2016-06-27 22:32:40 -07:00
snipe 084db22cd5 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-06-27 21:15:18 -07:00
snipe 081179a4fd Removed old JS libraries that aren't needed by v3 2016-06-27 21:15:11 -07:00
snipe 82d19fc704 Merge pull request #2201 from dmeltzer/fix-user-creation-values
UserController::postCreate - Store all request information.
2016-06-27 21:12:49 -07:00
Daniel Meltzer b1c28d7965 Move checks back into methods instead of having an extra helper method. Also remove unnecessary lock_passwords checks because there is a check at the top of the method that does this already. 2016-06-28 00:11:59 -04:00
snipe 6ea74f9fc3 Merge pull request #2203 from dmeltzer/display-error-if-import-upload-fails
If the move of the uploaded import file fails, return an error message.
2016-06-27 20:55:51 -07:00
Daniel Meltzer 278be52f7b Show the exception message if APP_DEBUG is enabled. 2016-06-27 23:54:45 -04:00
Daniel Meltzer ee1f983114 If the move of the uploaded import file fails, return a message. Fixes an issue reported on gitter today where bad permissions on the upload directory didn't provide any feedback. 2016-06-27 23:37:15 -04:00
snipe e3fe80e2a5 Merge pull request #2202 from dmeltzer/sqlite-fix-asset-edit
Fix integrity constraint violation on sqlite.
2016-06-27 20:20:01 -07:00
Daniel Meltzer d3b035cfe9 Fix integrity constraint violation on sqlite.
If the requestable checkbox was not checked, it did not exist in the request.
Setting requestable to null in such a case would cause a violation because it should be 0/1.

Also fix a copy/paste where we reset requestable after checking for rtd_location_id.
2016-06-27 23:16:03 -04:00
Daniel Meltzer cf29a4a319 Extract common data from UserController postCreate and postEdit into a helper method. Use this method to store data about user. Fixes #2200 2016-06-27 22:48:09 -04:00
snipe e9bb0e948b Merge pull request #2197 from dmeltzer/another-slack-fix
Link to user on asset checkout as well as checkin.
2016-06-23 19:23:59 -07:00
Daniel Meltzer 5bc52a9425 Link to user on asset checkout as well as checkin. 2016-06-23 09:39:50 -04:00
snipe 51a8fc1eee Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-22 17:18:16 -07:00
snipe 2867cd523d Fixes #2192 2016-06-22 17:14:49 -07:00
snipe 0cf563ae5b Show admin in maintenances 2016-06-22 17:04:47 -07:00
snipe 95beddf613 Use helper library for asset list 2016-06-22 16:58:36 -07:00
snipe e5a5de6a0d Just use inline validation instead of form request, since it's a one-off 2016-06-22 15:59:00 -07:00
snipe 0ca85f8a8a Updates to components 2016-06-22 14:55:17 -07:00
snipe 014e7ba9c4 Updated strings 2016-06-22 14:39:19 -07:00
snipe 2df3e95efc Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-22 14:19:30 -07:00
snipe 65dfd23021 Merge pull request #2191 from dmeltzer/importer-improves
Importer: Show the name of the item with errors in the table.
2016-06-22 14:18:30 -07:00
Daniel Meltzer 25b916afeb Show the name of the item with errors in the table. 2016-06-22 17:09:04 -04:00
snipe 6673a5afe1 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-22 13:01:06 -07:00
snipe fdd17a2088 Fixed weird capitalisation of language strings 2016-06-22 12:58:29 -07:00
snipe 424b854e29 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-22 12:52:00 -07:00
snipe f753783ca0 Smaller miminums for model and category name 2016-06-22 12:50:21 -07:00
snipe 5daaa24a07 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-22 12:30:48 -07:00
snipe 4ed8ff5576 Formatting fixes for coding standards 2016-06-22 12:27:41 -07:00
snipe 70aefdc9c0 Merge pull request #2190 from dmeltzer/fix-asset-creation
Flash input on model validation errors when creating/editing assets.
2016-06-22 12:23:13 -07:00
Daniel Meltzer f6d47887c4 Flash input on model validation errors when creating/editing assets. 2016-06-22 15:20:49 -04:00
snipe 8942e085c3 Merge pull request #2189 from dmeltzer/importer-improvements
Two more importer fixes.
2016-06-22 12:20:13 -07:00
snipe 3470fd57ef Merge pull request #2188 from dmeltzer/paveit-syntax-fix
Add a space to the signature to make the --soft option work.
2016-06-22 12:16:25 -07:00
Daniel Meltzer eba6574047 Add a space to the signature to make the --soft option work. 2016-06-22 15:13:43 -04:00
Daniel Meltzer 43e64a5f8c Store a list of errors associated with each field instead of overwriting the error if multiple occur. Also Adjust the importer to extract the asset tag earlier in the process so all asset related errors are associated with the asset tag rather than some being tied to the name. 2016-06-22 15:13:01 -04:00
snipe 71b82fee03 Merge pull request #2187 from dmeltzer/fix-asset-creation
Fix asset creation errors when asset tag already exists
2016-06-22 11:31:48 -07:00
Daniel Meltzer b9f72a2afa Flash errors to session on edit as well. 2016-06-22 12:55:09 -04:00
Daniel Meltzer 560115e758 If we survive form request validation but fail model validation, ensure that the errors are actually flashed to the session. Another thing that will be better fixed in the future when handling json nicer. 2016-06-22 12:55:09 -04:00
snipe dd1241f964 Fix in case crated_at is blank 2016-06-21 17:19:46 -07:00
snipe dcdc1a6e7b Merge pull request #2185 from dmeltzer/slack-fixes
A few slack fixes
2016-06-21 15:45:22 -07:00
snipe 50e38cb740 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-21 12:22:49 -07:00
snipe 508e7acb54 Bump up memory for LDAP import of large number of users 2016-06-21 12:22:10 -07:00
snipe e9227f77b6 Fixes #2163 - put model image in view if no asset image 2016-06-21 12:20:22 -07:00
snipe 3107b3679d Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-21 11:09:31 -07:00
snipe 49bf9f8b5b Switch null to lowercase for code style adherence 2016-06-21 11:06:53 -07:00
snipe 133d5e34a9 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-21 10:07:37 -07:00
snipe 9c5965a8c5 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-21 10:06:29 -07:00
snipe afc3cfa16a Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-06-21 10:06:19 -07:00
snipe c9bdc7da8e Merge pull request #2176 from dmeltzer/fix-importer-user
Assorted Importer Fixes
2016-06-21 10:04:06 -07:00
snipe 37d22d6d21 Merge remote-tracking branch 'origin/v3-master' into v3 2016-06-21 10:03:45 -07:00
snipe b152927dd0 Merge pull request #2164 from rassie/v3-master
Fix reverse proxy support
2016-06-21 10:03:10 -07:00
Daniel Meltzer f004facb06 A few slack fixes
1) Missing $admin_user in AccessoriesController::postCheckout().  Fixes #2183
2) AssetsController::postCheckin used the hardware url for the user link, not the user url
2016-06-21 09:43:32 -04:00
Daniel Meltzer d6dd449445 Only show importer progress if on command line. It broke error display from web. 2016-06-20 00:09:17 -04:00
Daniel Meltzer 8c00bad6d0 Add a check to ensure custom fields exist before iterating through them 2016-06-20 00:09:17 -04:00
Daniel Meltzer 4715cc6447 Pass user id to importer. This shows items imported through web interface as created by the appropriate user. Also save warranty_months to item, not just read it from csv. Fixes #2175 2016-06-20 00:09:17 -04:00
snipe 6165d804f9 Merge pull request #2145 from dmeltzer/disable-select2-on-ios
Disable select2 on ios.
2016-06-17 17:15:47 -07:00
snipe 161c6fe2e6 Merge pull request #2173 from twistedR/fix-password-login
Use app.url for password reset instead of hard coded one.
2016-06-17 17:15:05 -07:00
snipe 1c51db876c Merge pull request #2172 from ddreier/v3-label-changes
Center 1D Barcode and include Custom CSS in barcodes view
2016-06-17 17:14:28 -07:00
snipe f26c24ea35 Merge pull request #2171 from dmeltzer/fix-asset-maintence-validation
Use the model validation trait to validate asset maintences
2016-06-17 17:14:00 -07:00
snipe 48595e3d76 Merge pull request #2135 from YetAnotherCodeMonkey/v3
Swap bgutter and sgutter as they seem to be reversed.
2016-06-17 17:12:47 -07:00
Raveesh bb3d88cce5 Use the full app.url for the password link 2016-06-17 17:52:14 -04:00
Daniel Dreier 52084a2c24 Add CSS to center the 1D barcode and add PHP to include the custom CSS from Settings. 2016-06-17 14:38:50 -05:00
Daniel Meltzer 5a45ec708b Use the model validation trait to validate asset maintences. Might be better to add a form request as well, but this at least makes the model validation occur. fixes #2170 2016-06-16 22:22:07 -04:00
Nikolai Prokoschenko 8d03668d78 Fix reverse proxy support
Reintroducing trusted proxies via fideloper/proxy:

* Upgraded fideloper/proxy to 3.1
* Added fideloper/proxy to Http/Kernel.php
* Added fideloper/proxy to config/app.php
* Added environment variable APP_TRUSTED_PROXIES to env (with '*' being the default fallback)
2016-06-16 15:43:42 +02:00
snipe 4a148ac069 Codacity badge 2016-06-15 21:23:58 -07:00
snipe 973513a078 Remove unecessary log use statement 2016-06-15 21:18:40 -07:00
snipe 412756b651 Fix link to view manufacturer in hardware view 2016-06-15 21:14:26 -07:00
snipe 416cd96c94 Removed debugging loggin in middleware 2016-06-15 21:08:19 -07:00
snipe 87352470c0 Added sortable created_at to assets and users 2016-06-15 21:06:17 -07:00
snipe 27427dd26b Additional comments to clarify permissions middleware 2016-06-15 20:57:16 -07:00
snipe e2789b2951 Protect users routes 2016-06-15 20:45:57 -07:00
snipe 6a277a5391 Added inheritance back into users/groups 2016-06-15 20:45:45 -07:00
snipe 464ecc7cc6 Moved group sync 2016-06-15 11:51:10 -07:00
snipe 1efa69e51f Fixes #2158 2016-06-15 11:50:57 -07:00
snipe 6253d41231 Merge pull request #2151 from dmeltzer/pull-from-v3-master
Change v3 installer to fetch v3 master.
2016-06-13 22:55:41 -07:00
snipe b4d6842a7c Minor formatting changes, added DB call for custom fields 2016-06-13 21:45:52 -07:00
snipe f3e42384c5 Hardcoded higher PHP execution limits 2016-06-13 21:41:09 -07:00
snipe c29984d0df Skip superuser check if the user isn't logged in 2016-06-13 19:05:29 -07:00
Daniel Meltzer 77f6fe161e Change install.sh in v3 to pull the v3 script 2016-06-13 21:58:06 -04:00
Daniel Meltzer 9b08d99fa4 Fetch the current v3-master zip file, not the alpha2 one. 2016-06-13 21:54:32 -04:00
snipe 0fd43c0a5d Updated language strings 2016-06-13 12:16:43 -07:00
snipe 3ca81f4d73 Fixes #2140 2016-06-13 12:07:01 -07:00
snipe bfe4bc6ee5 Bypass company scoping if user is an admin 2016-06-13 11:40:22 -07:00
snipe dec95c3e06 Updated blade for box panel 2016-06-13 11:39:57 -07:00
snipe 2df71be321 No need to update the user again 2016-06-13 11:30:47 -07:00
snipe 396446a34b Updated namespace for collection 2016-06-13 10:54:28 -07:00
snipe 2daed3c271 Fix for custom fields not saving 2016-06-10 16:36:46 -07:00
snipe c1a3592059 Fixes #2130 2016-06-10 08:29:43 -07:00
snipe 57c9d506b8 Fix namespacing for actionlog 2016-06-10 07:57:54 -07:00
snipe 5904de8718 Remove asset tag requirement from form request
It donks the edit screen as it thinks the asset tag has already been taken
2016-06-10 05:54:20 -07:00
snipe ac15fb9be9 Merge pull request #2147 from dmeltzer/Fix-Asset-Creation-with-old-data
Fix editing assets.
2016-06-10 05:51:33 -07:00
Daniel Meltzer 2159d77fc2 No longer necessary. 2016-06-10 07:46:38 -05:00
Daniel Meltzer e9605891f3 Merge upstream and fix changes. 2016-06-10 07:44:45 -05:00
Daniel Meltzer 9c4c91063f Merge branch 'v3' into Fix-Asset-Creation-with-old-data 2016-06-10 07:35:30 -05:00
Daniel Meltzer 4e74c553bd Fix editing of assets. This also uses the asset form request for validation. 2016-06-10 07:33:33 -05:00
snipe 9e8b76d348 Use updated $request->input methods for 5.2 2016-06-10 05:16:27 -07:00
snipe 6fa4d1252d Fixes purchase date if no purchase date given 2016-06-10 05:00:49 -07:00
snipe 7a9cfb1a8f Fixed label weirdness when no serial 2016-06-10 04:43:17 -07:00
snipe a0901247a3 Let superadmins through companyable trait 2016-06-10 04:07:27 -07:00
snipe 02a9394cd9 Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-10 03:41:03 -07:00
snipe ec4bc6c2af Allow superadmins to print labels 2016-06-10 03:40:49 -07:00
snipe 4e1472f66d Merge remote-tracking branch 'origin/v3' into v3-master 2016-06-10 00:48:33 -07:00
snipe c6ca1748cb Merge pull request #2146 from dmeltzer/Fix-Asset-Creation-with-old-data
Fix hardware creation error making old input disappear.
2016-06-10 00:47:30 -07:00
Daniel Meltzer 25c10c43dd Disable select2 on ios. It's terribly slow, doesn't register click events, and has forces focus to the search bar by default (which makes the keyboard popup and take over the screen. The latter issue might justify disabling it for all mobile devices, but the performance issues certainly justify it on iOS. 2016-06-09 20:31:23 -05:00
Daniel Meltzer 044695cb02 Fix hardware creation error making old input disappear. This should be redone to dynamically update on the client side based on a JSON response instead of flashing and reloading, but that's a lot of change for v3 at this point. 2016-06-09 20:28:49 -05:00
snipe f44d98924d Removed erroneous call to nonexistent model 2016-06-09 14:42:13 -07:00
snipe 66adffe6d9 Moved include 2016-06-09 14:41:58 -07:00
snipe c91c1f92cd Fixes #2132 2016-06-09 13:27:50 -07:00
snipe bbb116f29c Fixes #2142 2016-06-09 12:25:51 -07:00
snipe a04d6293d1 Proper hypenation of Snipe-IT in footer 2016-06-09 03:08:42 -07:00
snipe 845b182fdf Fixes format for users in category view 2016-06-09 02:26:43 -07:00
snipe 2b5fb04ba9 Allow admin to add user on checkout screen 2016-06-09 00:36:52 -07:00
snipe bb758d618b Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-06-08 23:28:53 -07:00
snipe 9b2c7d749b Fixed barcode descriptions 2016-06-08 23:28:44 -07:00
snipe 51742d66df Removed uneeded size array 2016-06-08 23:28:21 -07:00
snipe 3a101aa0c8 Merge pull request #2131 from dmeltzer/fix-license-checkout
Fix license Checkout.
2016-06-08 18:01:16 -07:00
Drew Wilkinson 7f22d3f486 Fix margin for bottom to not be equal to side gutter, looks like a typo 2016-06-07 13:03:21 -04:00
Drew Wilkinson c9d6857c73 Swap bgutter and sgutter as they seem to be reversed. I assume s=side=horizontal and b=bottom=vertical... 2016-06-07 12:39:53 -04:00
Daniel Meltzer 9648c6f1d3 Fix license Checkout.
A mistake in the sqlite porting led to "Please select an asset"
disappearing.  This centralizes that code in Helper, and uses the code
in Licensescontroller and componentscontroller.

Also use the proper name on the components checkout page.

AssetMaintencesController reuses the same underlying code as
licensescontroller, but we don't want "Please select an asset" to be an
option there, so I'm not changing that code.
2016-06-07 07:58:08 -05:00
snipe 75eb2bbe09 Janky-ass form request stuff 2016-06-06 21:02:06 -07:00
snipe d4e231d5d4 Save permissions on new user 2016-06-06 18:56:43 -07:00
snipe 75dfb87671 Use form request for user add/edit to handle password and password confirmation 2016-06-06 14:15:50 -07:00
snipe 23936e465d Merge pull request #2123 from dmeltzer/fix-setup-on-windows
Fix missing posix_getpwuid on windows.
2016-06-06 12:31:30 -07:00
snipe 13d11bfdcc Merge pull request #2121 from dmeltzer/add-soft-pave
Add a 'soft' delete option to the pave tool.
2016-06-06 12:30:06 -07:00
snipe 21506f4101 Merge pull request #2120 from dmeltzer/add-clone-to-models-index
Add clone action to Assetmodels index page.
2016-06-06 12:29:54 -07:00
snipe 51ab8ce41c Merge pull request #2119 from dmeltzer/fix-category-lists
Modify Helper::categoryList() to take a category type parameter.
2016-06-06 12:29:31 -07:00
Daniel Meltzer ea3e11e011 Fix missing posix_getpwuid on windows.
This isn't a perfect solution.  It basically just nullifies the check on
windows.  I'm not sure if IIS can run as a nonelevated user though, so
perhaps thats the best choice.  Regardless, this fixes the setup.
2016-06-06 07:43:05 -05:00
Daniel Meltzer 6ba37a3a8d Add a 'soft' delete option to the pave tool. This leaves db structure and migrations in place but removes everything inside the db except the first user. 2016-06-05 10:24:42 -05:00
Daniel Meltzer a89511674b Add clone icon to Assetmodels index page. 2016-06-05 10:00:31 -05:00
Daniel Meltzer cd9cca9c6b Modify Helper::categoryList() to take a category type parameter.
This allows for centralizing the category fetching code more and fixes
an error in asset model viewing (#2118).  Also add a few translated
strings and standardize on a base of 'Select a *' for the default value
in our lists.
2016-06-05 09:47:44 -05:00
snipe 9f6eb02afc Don't purge users where show_in_list = 1
This is necessary so hosted customers can't hard-delete my account :-/
2016-06-03 12:13:59 -07:00
snipe f8ac9a3f77 Fixes #2110 2016-06-03 11:48:20 -07:00
snipe b28d966645 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-06-02 21:16:48 -07:00
snipe 030b525535 Small readme changes 2016-06-02 21:16:43 -07:00
Brady Wetherington 093bcdfe4f Fix to Dockerfile build; backup path must've changed. 2016-06-02 21:10:50 -07:00
Brady Wetherington 5e0cc241a0 Forgot to add the new docker.env file 2016-06-02 20:35:05 -07:00
snipe 7d5c7991f4 Create backups directory 2016-06-02 19:45:59 -07:00
snipe 9ced24b127 Bumped version for RC-3 release 2016-06-02 19:06:54 -07:00
snipe fd32f6d4d5 New language strings 2016-06-02 19:01:09 -07:00
snipe c5d96812f3 Fixed erronerously removed save methods 2016-06-02 17:22:23 -07:00
snipe 6de6052185 Hardcoded page number to prevent error 2016-06-02 17:17:50 -07:00
snipe 402c955f1c Fixed title 2016-06-02 17:17:42 -07:00
snipe 2f8cbe4ac2 Better default mysqldump path 2016-06-02 17:17:33 -07:00
snipe 95f94c1cfb Fixed error when user has no permissions values 2016-06-02 17:16:22 -07:00
snipe 485fb26393 Fixes #1985 - disallow checkin/checkout if the asset is not in a deployable status 2016-06-02 14:04:54 -07:00
snipe 9551c07528 Fixes #2087 - bad route to maintenance edit 2016-06-02 11:18:17 -07:00
snipe 2d5a0deb31 Eager loading for requestable assets account page 2016-06-02 02:57:22 -07:00
snipe 7d2ea36997 Use permission gates on routes 2016-06-02 02:50:00 -07:00
snipe 97691726f0 Updates to permissions decoding 2016-06-02 02:49:32 -07:00
snipe dce549cc5c Updated debugbar prefs 2016-06-02 02:49:17 -07:00
snipe 049e13e365 Switch to gate for permission check 2016-06-02 02:48:52 -07:00
snipe dddb0f7267 Fixed group error message 2016-06-02 02:46:49 -07:00
snipe 5de6b8e016 Added gates to authservice provider for finer tuned permissions 2016-06-02 02:40:49 -07:00
snipe a3e9b3df86 Updated error page title 2016-06-02 02:39:44 -07:00
snipe 89e656e709 Switched to can/cannot for blade 2016-06-02 02:39:36 -07:00
snipe 5f5fddb7a4 Updated permissions array 2016-06-02 02:39:23 -07:00
snipe 46d3a784a2 Fixes groups for cloning users 2016-06-02 00:41:10 -07:00
snipe 4998b5ab1b Fixes #2080 2016-06-02 00:15:38 -07:00
snipe 368bb77cf0 Merge pull request #2102 from dmeltzer/layout-fixes
Improve navbar/header layout
2016-06-01 21:25:40 -07:00
Daniel Meltzer 37b416d5c7 Fix my git terrribleness. 2016-06-01 23:00:29 -05:00
Daniel Meltzer c7e695d3fe Revert "Move the breadcrumb thingy back inside the header. Remove it from a list item because it wasn't part of a list"
This reverts commit 9c77de6473.
2016-06-01 22:55:37 -05:00
Daniel Meltzer a152b0ae54 Center the logo text on small screens. It's looking more reasonable by the week... 2016-06-01 22:52:25 -05:00
Daniel Meltzer 9c77de6473 Move the breadcrumb thingy back inside the header. Remove it from a list item because it wasn't part of a list 2016-06-01 22:41:11 -05:00
Daniel Meltzer 71ca17649c Improvements? 2016-06-01 22:30:12 -05:00
Daniel Meltzer 41f3d5ccbc Add new css file 2016-06-01 21:42:48 -05:00
Daniel Meltzer e32d5490d3 Add updated gulp css for testing. Probably revert before merge. 2016-06-01 21:39:49 -05:00
Daniel Meltzer d85d3b14f7 More layout fixes for small devices. 2016-06-01 21:37:03 -05:00
snipe 1daa6abf48 Merge pull request #2101 from dmeltzer/importer-again
Case insensitive string comparison for items when importing
2016-06-01 18:13:02 -07:00
Daniel Meltzer 5d206f2c20 Fix navbar spacing on screen and mobile. Move the items on the left of the navbar to their own list. Style fixes. Move breadcrumb to outside navbar because it was breaking things and I think it looks better 2016-06-01 20:10:19 -05:00
Daniel Meltzer 2ff1ee4d33 Fix some indentaiton and a missing tag, no functionality changes here. 2016-06-01 20:10:19 -05:00
snipe 04610e7864 Just use model validation for new user 2016-06-01 18:04:11 -07:00
Daniel Meltzer da01591ab8 Case insensitive string comparison for items when comparing with existing items. Fixes some false errors. Also remove stray characters from manufacturer logging. 2016-06-01 19:31:24 -05:00
snipe cffa76e627 Find first record, instead of hardcoded id 1 2016-06-01 15:50:50 -07:00
snipe 9c4cd9c3ce Save email/username format in settings controller 2016-06-01 15:45:26 -07:00
snipe eacf70ee3f Updated validation 2016-06-01 15:45:05 -07:00
snipe 33a35ec7f5 Migration for for email/username format settings 2016-06-01 15:44:37 -07:00
snipe e0c07d8921 Language strings for email/username format 2016-06-01 15:44:29 -07:00
snipe 99f6207a69 Added macro for email/username format 2016-06-01 15:44:16 -07:00
snipe d786be4fc0 Use local fontawesome and added select2 2016-06-01 15:43:55 -07:00
snipe 8a7a659a87 Added email domain, email format and username format to settings/setup form 2016-06-01 15:43:39 -07:00
snipe f3c6275f8d Removed settings form request 2016-06-01 15:43:12 -07:00
snipe 0a2fb2ace7 Merge pull request #2099 from dmeltzer/sqlite-fixes
Fix a regression in Helper::usersList and ::managerList()
2016-06-01 11:49:51 -07:00
Daniel Meltzer 1c1ef951e9 Fix a regression in Helper::usersList and ::managerList() where the "Select a User" option disappeared. Also format names the way they used to be formatted. 2016-06-01 13:47:46 -05:00
snipe 45d3d90c94 Merge pull request #2067 from dmeltzer/ajax-mobile-upload-PR
Mobile-Friendly image capture/upload + Ajax rewrite of asset create
2016-06-01 11:34:42 -07:00
snipe a9870db83f Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-31 21:16:40 -07:00
snipe 697ed0d53c Fixes UAT for User
Needed to specify form name to prevent focus in asset tag search from being submitted
2016-05-31 21:16:30 -07:00
Daniel Meltzer 3ddaa88694 Fix image processing when editing an existing asset. Also reenable the image scaling on the server, but boost limit to 800x800 2016-05-31 19:50:58 -05:00
Daniel Meltzer b3454b1c24 Fix bug in image process logic that wouldn't resize the height. Also make it possible to choose files from android as well as pictures directly. 2016-05-31 19:50:58 -05:00
Daniel Meltzer fcc79456fd Play with a mobile friendly capture-image-from device when adding an asset. This also involved rewriting the upload to be all ajaxy and stuff 2016-05-31 19:50:58 -05:00
snipe 11c400f12b Merge pull request #2095 from dmeltzer/importer-improvements
Reduce Import error warnings in importer.
2016-05-31 17:45:29 -07:00
snipe 823273f565 Merge pull request #2092 from dmeltzer/installer
Fix installer for v3.  Tested with centos7 and ubuntu 16.4.
2016-05-31 17:45:18 -07:00
snipe a542b18a04 Merge pull request #2050 from dmeltzer/sqlite-fixes
Sqlite fixes
2016-05-31 17:45:04 -07:00
Daniel Meltzer f2a5337ad2 Simplify 2016-05-31 19:41:14 -05:00
Daniel Meltzer 4af5cdd64f asset_id is not allowed to be null in asset_log according to db schema. 0 it out here to make sqlite happy. 2016-05-31 19:41:14 -05:00
Daniel Meltzer 0fa82743a1 Remove remaining DB::Raw(concat) calls to make things more sqlite friendly. This adds one new method to the Asset Model to return the formatted string that was used by the license and asset maintence controller. It also fixes a potential sqlite-only issue where '' and null are different. 2016-05-31 19:41:14 -05:00
Daniel Meltzer 45d93ffa8c Use a transaction while creating license seats. Makes adding a license with a large number of seats much more managable. 2016-05-31 19:41:14 -05:00
Daniel Meltzer 4b98711e07 Replace the assorted concat() methods with a full_name method in the User model and adjust queries accordingly 2016-05-31 19:41:14 -05:00
Daniel Meltzer a729038ccd Fix typo. 2016-05-31 19:00:11 -05:00
Daniel Meltzer e5bd6a8a26 A bit more detailed message when starting the installer to share what version of OS we've detected. 2016-05-31 18:51:56 -05:00
Daniel Meltzer 5e03fe40a7 Fix some more centos6 stuff.
Fix for detecting centos6.  Not ideal, but hopefully no one has a fresh install of centos5 lying around..

Also fix some issues with code not being ported in the centos6 section.
2016-05-31 18:45:07 -05:00
Daniel Meltzer dab2a50982 Only display errors in import table if things actually prevent the asset from being created. Also some table formatting improvements. 2016-05-31 18:04:01 -05:00
snipe 0e0b31bba6 Company name length to 1 2016-05-31 15:04:13 -07:00
snipe c9d00b1f06 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-31 14:27:39 -07:00
snipe 9bb258bb99 Updated alt tag 2016-05-31 14:27:33 -07:00
snipe ac10a199ea Merge pull request #2083 from dmeltzer/importer-improvements
Importer improvements
2016-05-31 14:25:33 -07:00
Daniel Meltzer 5952181454 Fix missing -p in mysql call on centos6. 2016-05-31 09:05:51 -05:00
Daniel Meltzer 0da1e186d7 Fix some weird bash issues caused when merging the v2 and v3 versions of the script. 2016-05-29 15:54:20 -05:00
Daniel Meltzer d92de14413 Fix installer for v3. Tested with centos7 and ubuntu 16.0.4.
This essentially just changes the configuration section to work with the
new .env file, and leaves almost everything else alone.  Some
reordering of code did occur to try and fix a number of issues I
encountered along the way.  This still really needs to be rewritten to
only run what it should as root, and not everything, but that should get
more testing than there is between now and v3.

One thing to note: This changes fetching master.zip to the v3 alpha2
tag, for obviousish reasons.  Once master goes back to v3, or there is a
way of downloading a v3 tarball on a regular basis, it should be changed
to do that again.
2016-05-28 20:35:28 -05:00
Daniel Meltzer 004c63cd5d Improve web imported. Show a list of all items with that were not imported correctly after import. Modify ObjectImporter and add a web-import parameter that causes it to spit out json errors exclusively. Long term I want to separate the console command and the logic so we aren't calling the console command directly, but rather a class that does everything. This would allow for easier progress reports and ajaxification. 2016-05-26 21:29:29 -05:00
Daniel Meltzer 715e385925 Two things. One, try to make the import uploads directory if it doesn't exist. Two, call the object importer instead of the old asset importer. TODO: Feed output from object importer back to import page. 2016-05-26 08:00:00 -05:00
Daniel Meltzer 891c37b2ed Add warranty months. Also fix a merge issue where things reverted back to comment instead of log. 2016-05-25 21:13:26 -05:00
Daniel Meltzer e353df588f Importer improvements. If user real name doesn't exist don't try to create the user. 2016-05-25 20:47:46 -05:00
Daniel Meltzer fd0d04eba4 Import status labels. 2016-05-25 20:46:01 -05:00
Daniel Meltzer 22c6f32e92 Instead of a field in the csv, set whether assets, consumables, or accessories are generated by an option on the command line. Also Adjustconsumables/accessories to function smoother. 2016-05-25 20:37:19 -05:00
Daniel Meltzer 04428d2d07 Replace console output in ObjectImporter with a logging mechanism. Also track all model/validation errors and output them at the end of the import, rather than inline. 2016-05-25 20:37:19 -05:00
snipe c89f357e4a Fixes #2082
LOL whoops
2016-05-25 13:32:33 -07:00
snipe 8a968b4dfb Responsive dashboard table 2016-05-24 19:04:56 -07:00
snipe 9aff515c0a More mobile fixes 2016-05-24 18:50:54 -07:00
snipe 5f91329397 Some responsive fixes
Still needs work tho :(
2016-05-24 17:59:02 -07:00
snipe 37be587c39 Make regular and highlight colors the same, since we're not using highlight colors in the pie chart yet 2016-05-24 16:19:44 -07:00
snipe 0c33575962 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-24 16:10:45 -07:00
snipe 84edc9cf25 New generated JS 2016-05-24 16:10:04 -07:00
snipe 14dac9b371 Updated versioned js 2016-05-24 16:09:37 -07:00
snipe 8e18d02f7a Updated chartJS 2016-05-24 16:09:28 -07:00
snipe d0ebdd03bd Added legend template for chartJS, even though it doesn't seem to do a fucking thing 2016-05-24 16:08:56 -07:00
snipe bfc3f69adb Better comments on model methods 2016-05-24 16:08:18 -07:00
snipe cde0d49e18 Added assets method 2016-05-24 16:06:22 -07:00
snipe abf027059f Fixed comment 2016-05-24 16:06:15 -07:00
snipe 4edc2a7a66 Route and controller for dashboard chart 2016-05-24 16:06:09 -07:00
snipe 3b838ca867 Added static colors for charts 2016-05-24 16:05:51 -07:00
snipe 8b023adba3 Merge pull request #2078 from dmeltzer/fix-statuslabels-translations
Fix strings for StatusLabels, they still referenced locations.
2016-05-24 15:56:10 -07:00
Daniel Meltzer 293b8c0dea Fix strings for StatusLabels, they still referenced locations. 2016-05-24 17:54:44 -05:00
snipe d6dc57286f Merge pull request #2077 from dmeltzer/fix-settings-table-for-sqlite
Fix (for real this time?) the settings table option_name/option_value
2016-05-24 15:45:25 -07:00
Daniel Meltzer 52b61c9d49 Fix mistake in the settings table kerfuffle. 2016-05-24 17:41:59 -05:00
snipe 780c0e678d Changed min dimensions to 500 from 300 2016-05-24 13:21:18 -07:00
snipe 5bceb5ce52 Display escaped parsedown note 2016-05-24 10:21:45 -07:00
snipe de5e1ca86b Add persedown helper 2016-05-24 10:21:33 -07:00
snipe 6c6e65b8ca Fixes #2076 2016-05-24 09:46:43 -07:00
snipe 64d818e56e Fixed License and LicenseSeat namespaces for importer 2016-05-24 02:17:10 -07:00
snipe d6715914e1 Fixed supplier namespace 2016-05-24 02:13:28 -07:00
snipe f10b3b7cdb Fix for license importer 2016-05-24 01:51:47 -07:00
snipe f844bf4b41 Nicer focus handling for asset search 2016-05-24 01:10:05 -07:00
snipe 6e006a6873 Redundant top nav 2016-05-24 00:58:59 -07:00
snipe cb91829729 Fixed division by zero error 2016-05-24 00:49:56 -07:00
snipe fb35e40342 Search by asset tag
Compatible with barcode scanners
2016-05-20 17:02:28 -07:00
snipe b796e72faf Remove old search 2016-05-20 16:01:23 -07:00
snipe c56ceebb40 Default timezone back to UTC 2016-05-20 14:29:15 -07:00
snipe 78fc6dec3c Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-20 12:23:36 -07:00
snipe 7fd6051514 Fixes #2062 - old permissions masks to new 2016-05-20 12:23:31 -07:00
snipe 072923826d Merge pull request #2060 from dmeltzer/fix-settings-table-for-sqlite
Fix updates from v2
2016-05-20 10:52:00 -07:00
Daniel Meltzer c52e3b5f9c Check if the column exists before dropping. Also recreate the column in a rollback to make the migrations happy. Also break into two migrations to make sqlite happy. 2016-05-20 10:03:04 -05:00
snipe f6cdd90e41 New docs links in README 2016-05-20 01:44:24 -07:00
snipe 975b266cb0 Icon display on recent activity 2016-05-20 01:17:00 -07:00
snipe aad1ba4ab3 Updated language strings 2016-05-20 00:47:03 -07:00
snipe 6b5d0a5abf Translations and nicer formatting for login/password reset 2016-05-20 00:25:45 -07:00
snipe 6724489be2 Added additional dump variables 2016-05-19 23:37:36 -07:00
snipe be0a60e049 Updated strings 2016-05-19 23:27:08 -07:00
snipe 3d1f051e16 Remove demo login info 2016-05-19 23:21:01 -07:00
snipe 66beeeb26d Added notes back to asset file uploads 2016-05-19 23:12:27 -07:00
snipe 2c7b345ad2 Merge pull request #2057 from dmeltzer/fix-settings-table-for-sqlite
Fix Settings Table for Sqlite
2016-05-19 20:27:56 -07:00
Daniel Meltzer a6849fc689 Remove stray code from my commit and add a migration to fix the Settings issue the proper way. 2016-05-19 21:52:49 -05:00
snipe db6305bf1f Merge pull request #2056 from dmeltzer/make-categories-limit-work
Make limit/offset work in getDataView
2016-05-19 19:50:22 -07:00
snipe cbcc155f27 Settings tweaks 2016-05-19 19:49:25 -07:00
Daniel Meltzer 1148750c9a Make limit/offset work in getDataView 2016-05-19 21:45:48 -05:00
snipe c4a699f109 Validation for new alert settings 2016-05-19 19:43:05 -07:00
snipe 2b1bf9f7f3 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-19 19:34:11 -07:00
snipe 15eb6df1db Add settings for alert interval threshold and inventory threshold 2016-05-19 19:33:53 -07:00
snipe 29e54830e1 Added 2D barcodes to labels 2016-05-19 19:12:42 -07:00
snipe 486d74fa64 Merge pull request #2052 from dmeltzer/remove-sentry-from-importer
Get Rid of sentry code in importer
2016-05-18 23:40:48 -07:00
Daniel Meltzer 592ce4c2de Readd sample.csv. Also port away from Sentry in the importer to be laravel5 compliant. 2016-05-18 23:33:18 -05:00
snipe 7fe020f836 Merge pull request #2051 from dmeltzer/importer-for-v3
Importer for v3
2016-05-18 20:59:26 -07:00
Daniel Meltzer 6b0bd52f5c Merge branch 'importer-for-v3' of github.com:dmeltzer/snipe-it into importer-for-v3 2016-05-18 22:41:58 -05:00
Daniel Meltzer 4f70fa88d9 Rename to snipeit:import 2016-05-18 22:40:02 -05:00
Daniel Meltzer 173c3de36a Add the asset to the cache after creating it as well. 2016-05-18 22:40:02 -05:00
Daniel Meltzer 2a56148ec2 Remove extraneuous htmlentities() calls, now that we call it in array_smart_fetch 2016-05-18 22:40:02 -05:00
Daniel Meltzer df749f26f5 Add the company/suppliers to the cache. This fixes some issues with duplicate items existing 2016-05-18 22:40:02 -05:00
Daniel Meltzer 191ae110d0 * Alphabetize the createOrFetch methods
* Move the html escaping to array_smart_fetch to avoid duplication
* Ensure string comparisons have === everywhere
2016-05-18 22:40:02 -05:00
Daniel Meltzer 5821127a79 Update/port ObjectImportComandd to work with v3. Also change to do one big transactional commit instead of writing to db after each item. Went from a 2 minute import to a 5 second import for a 2000 item file. I still need to do some more santization of the input and work on error handling, but this seems to be in decent shape. 2016-05-18 22:40:02 -05:00
snipe b2b3b3d5ad Hide bulk attributes for components (for now) 2016-05-18 20:39:53 -07:00
Daniel Meltzer 4dc83035c8 Rename to snipeit:import 2016-05-18 22:38:19 -05:00
Daniel Meltzer 1e948eabc8 Add the asset to the cache after creating it as well. 2016-05-18 22:37:59 -05:00
Daniel Meltzer 3b6f78f30c Remove extraneuous htmlentities() calls, now that we call it in array_smart_fetch 2016-05-18 22:33:55 -05:00
Daniel Meltzer 2e5e956810 Add the company/suppliers to the cache. This fixes some issues with duplicate items existing 2016-05-18 22:29:44 -05:00
snipe 5333c7083a More dashboard fixes 2016-05-18 19:48:19 -07:00
snipe c1c7fa143d Components display on assets page 2016-05-18 19:26:50 -07:00
snipe fb26188e41 Fixed dashboard for components 2016-05-18 19:16:43 -07:00
snipe 47c70141c7 Gross copypasta fix for #1932 2016-05-18 19:08:16 -07:00
snipe 23e416fd88 Make site name required 2016-05-18 18:24:28 -07:00
snipe 4ba2b89940 Add MS Excel as export
Excel does not work in Safari - known webkit issue, no fix :(
2016-05-18 18:14:40 -07:00
snipe f363ff35c6 Additional bootstrap tables files 2016-05-18 18:14:15 -07:00
snipe 0780f97807 Add multisort to assets 2016-05-18 16:48:46 -07:00
snipe b0b7cfa999 Better handling for show/hide columns in depreciation report 2016-05-18 16:06:29 -07:00
snipe 7ee13113e0 Add depreciation name and months to depreciation report 2016-05-18 15:59:54 -07:00
snipe 0568e979e8 If permissions are blank, don't error out on json_decode 2016-05-18 14:38:17 -07:00
snipe 8f1c4138d1 Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-17 21:16:18 -07:00
snipe 631aade6c4 Cleaned up language strings for categories 2016-05-17 21:16:12 -07:00
snipe 0ea5b090af Fixes issue with HTTPS key not found on non-HTTPS installs 2016-05-17 21:15:48 -07:00
snipe f9572ffa0c Fixes #2048 2016-05-17 21:15:29 -07:00
Daniel Meltzer e42cfc7601 * Alphabetize the createOrFetch methods
* Move the html escaping to array_smart_fetch to avoid duplication
* Ensure string comparisons have === everywhere
2016-05-17 21:47:38 -05:00
Daniel Meltzer fbed1a9d1a Update/port ObjectImportComandd to work with v3. Also change to do one big transactional commit instead of writing to db after each item. Went from a 2 minute import to a 5 second import for a 2000 item file. I still need to do some more santization of the input and work on error handling, but this seems to be in decent shape. 2016-05-17 21:25:17 -05:00
snipe e13042a9e9 Merge pull request #2045 from dmeltzer/fix-installer-for-ubuntu
Add support for Ubuntu 16.04
2016-05-16 21:56:02 -07:00
snipe ed9c6183c1 Updated language files 2016-05-16 21:54:13 -07:00
Daniel Meltzer 3e56ace3ee Add support for Ubuntu 16.04. Also rework version/os detection. This should work on centos, but I do not have an install to check with. Needs testing by someone that does! 2016-05-16 23:22:33 -05:00
snipe e552c36a0a Add model_no, item_no, and manufacturer to consumables 2016-05-16 17:11:31 -07:00
snipe 63f4bbe412 Temporarily remove clone option from categories view 2016-05-14 18:06:49 -07:00
snipe f6c2f9d84e Uploads gitkeep 2016-05-14 17:49:03 -07:00
snipe 93294583f8 Clean up gitignore 2016-05-14 17:48:03 -07:00
snipe b5a1e261e5 Added gitkeep for users dir 2016-05-14 17:40:41 -07:00
snipe 0a2555ed2c Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-14 17:26:17 -07:00
snipe 8b072fddcf Fixes middleware for locale 2016-05-14 17:25:56 -07:00
snipe a6186ff5bc Merge pull request #2043 from snipe/docker-v3
Docker v3
2016-05-14 16:53:06 -07:00
Brady Wetherington 008482203e Fixes to Dockerfile, updated docker/develop.sh for new options. 2016-05-14 16:46:53 -07:00
snipe 415b60a293 Added check for setup in Setting model 2016-05-14 16:09:00 -07:00
Brady Wetherington f03ecd9d08 Update docker support for upcoming v3 2016-05-14 15:43:46 -07:00
snipe 5b829884b8 Remove commented out js 2016-05-14 15:06:27 -07:00
snipe 8b0393ab52 Fontawesome animations 2016-05-14 15:06:16 -07:00
snipe 8ca71df7c9 Check for superuser 2016-05-14 15:05:35 -07:00
snipe 9a8e4a55e7 Check for DB table 2016-05-14 15:05:28 -07:00
snipe 1a14abed05 Check that the table exists
Should probably find a way to handle this that doesn't require a DB call
2016-05-14 15:05:20 -07:00
snipe 4dd3a95b6d Fix https detection 2016-05-14 15:04:59 -07:00
snipe beed74c0d0 Add extra tables for drop 2016-05-14 15:04:51 -07:00
snipe f4490b14f8 [Feature] Re-order custom fields (drag and drop) 2016-05-14 14:06:59 -07:00
snipe 72d54bdb88 Fixed formatting on license checkin/checkout 2016-05-12 21:03:53 -07:00
snipe a726934cde Fixed bulk delete+checkin for users 2016-05-12 21:01:31 -07:00
snipe ae0e7b9078 Updatd documentation links, use https 2016-05-12 18:06:19 -07:00
snipe 252b114b5f Fixed case sensitive model for status labels 2016-05-12 17:23:51 -07:00
snipe 73327d31e3 Updated backup paths for config variables in laravel-backups 3.7.0 2016-05-12 17:16:10 -07:00
snipe 1acfd525e8 Fixed stupid parse error 2016-05-12 17:12:52 -07:00
snipe cfe38322b9 Get backups to work again
This is still a littlw wonky tho :(
2016-05-12 17:11:26 -07:00
snipe 9cfde523b0 Updated laravel-backup package
Files are still not being generated. Open a ticket with the package maintainer
2016-05-12 16:54:07 -07:00
snipe 1773f671da Ignore laravel backups dir 2016-05-12 16:20:39 -07:00
snipe b9b8149234 Minor backups fixes 2016-05-12 16:20:23 -07:00
snipe 720274446e Fixes #1997 - save user groups without Sentry crap 2016-05-12 15:26:48 -07:00
snipe 6d91774943 [Feature Request] Fixes #2030 - allow asset name change on checkin 2016-05-12 12:34:44 -07:00
snipe a96947efa9 Possible fix for #2037
via https://github.com/laravel/framework/issues/8565#issuecomment-151171239
2016-05-12 12:06:22 -07:00
snipe 062cbeb18f Fixed bug in categories asset listing for hardware 2016-05-12 10:39:19 -07:00
snipe ae8a03fec3 Add manufacturer name/sorting/searching on assets 2016-05-12 10:38:57 -07:00
snipe c41b47902e Merge branch 'v3' of github.com:snipe/snipe-it into v3 2016-05-09 15:41:05 -07:00
snipe c56c398d4c Fixes #1996 - replace old Sentry methods with laravel native 2016-05-09 15:40:27 -07:00
snipe a144fb77cd Fixed hodor 2016-05-09 15:38:29 -07:00
snipe 2222aeacac Merge pull request #2012 from snipe/v3_fix_ubuntu_version_in_docker
Pin down Ubuntu version for dockerfile in v3
2016-05-05 12:46:26 -07:00
Brady Wetherington a2ebc0d983 Pin down Ubuntu version for dockerfile in v3 2016-05-05 12:45:00 -07:00
snipe d40289fbc9 Fixes #1997 and #1996 - replace sentry functions 2016-04-28 21:59:43 -07:00
snipe ba01b20ad4 Use updated redirect() reference 2016-04-28 21:06:41 -07:00
snipe 8dd0e72284 Remove erroneous comment 2016-04-28 21:05:45 -07:00
snipe d927aa3273 Fix delete method for groups 2016-04-28 21:03:56 -07:00
snipe a0bff94de3 Moved selectedPermissionsArray 2016-04-28 20:57:07 -07:00
snipe 7d8af579cf Updated controller with correct helper namespace 2016-04-28 20:57:02 -07:00
snipe 7783471cc3 Move selectedPermissionsArray to helper, since it can be used by users as well 2016-04-28 20:56:47 -07:00
snipe 8dc0dc0a07 Update permissions for cli user tool 2016-04-28 20:56:27 -07:00
snipe e6cbafe5ff Suppress console warning 2016-04-28 20:19:31 -07:00
snipe 7b489ad1ec Ability to suppress users from checkoutable list 2016-04-28 20:19:22 -07:00
snipe 449163c875 Fixes #1995 - updated group admin to use native permissions 2016-04-28 14:03:54 -07:00
snipe 97a91e2d83 Fix setting namespace 2016-04-25 12:15:41 -07:00
snipe 898d9ad025 [Feature] Added Supplier and Assigned to in asset email alert
[Bugfix] Fixed escaping for email templates for L5.2
2016-04-23 04:04:03 -07:00
snipe b250e2b5f0 [Bugfix] Fixed escaping for email templates for L5.2 2016-04-23 04:03:26 -07:00
snipe 32c193b9bf [Bugfix] Fixed Mail namespace 2016-04-23 04:02:52 -07:00
snipe c3b7332e3b [Bugfix] Fixed Mail namespace 2016-04-23 04:02:40 -07:00
snipe 96911b9e57 Fixes #1944 - add manufacturer to model list 2016-04-23 03:34:49 -07:00
snipe 3eb09871cf Fixed model name 2016-04-23 03:12:39 -07:00
snipe 1b5ef695f2 Add custom fields to modals in create asset 2016-04-23 03:12:31 -07:00
snipe 97e218541b Fixes date sanity check in checkout 2016-04-23 02:36:21 -07:00
snipe 30c6657fc1 Fixes date selector box 2016-04-23 02:36:08 -07:00
snipe 7a65fe8f89 Only get fieldset rules if there if is a model selected 2016-04-23 02:35:31 -07:00
snipe 93e7715c28 Fixes dumb timestamp if the user manually removes date 2016-04-23 02:34:29 -07:00
snipe 895fbb76bf Nicer error message formatting 2016-04-23 02:34:08 -07:00
snipe 7e0ab645bf Removed junk text 2016-04-23 02:09:52 -07:00
snipe 4d4b4ffd36 Use new checkout/checkin method 2016-04-23 02:08:38 -07:00
snipe 466f660a63 Removed older commented out code 2016-04-23 02:08:18 -07:00
snipe aa13b24bbc Remove Parsefloat. Again. 2016-04-23 02:08:04 -07:00
snipe 8179fc2f90 Changed checkout method to be more generic, for checkin and checkout 2016-04-23 02:07:40 -07:00
snipe 66a5050143 Fixed field name on checkin form 2016-04-23 02:06:57 -07:00
snipe c9d285cf47 Fixed float for purchase_cost 2016-04-21 22:23:08 -07:00
snipe b02cb91ae6 Tighter form display (offset-2) 2016-04-21 22:15:09 -07:00
snipe c9252989a1 Added red highlight back to superadmins 2016-04-21 21:59:50 -07:00
snipe e72d61d896 Checkin and Delete button 2016-04-21 21:56:28 -07:00
snipe d009c66c8b Fixed bulk user delete display 2016-04-21 21:53:31 -07:00
snipe 4b6f657739 Nicer purge box design 2016-04-21 21:53:22 -07:00
snipe ed8c72b946 Checkin and Delete User string 2016-04-21 21:53:13 -07:00
snipe 44f7305e12 Fix restore assets 2016-04-21 21:01:57 -07:00
snipe 6b982ec253 Check for accessories 2016-04-21 21:01:45 -07:00
snipe 8900672181 Nicer select2 box 2016-04-21 21:00:45 -07:00
snipe e1cca75f57 Updated from alert to callout 2016-04-21 20:52:53 -07:00
snipe a0b080b91d Fixed restore again.
For some reason, $user->restore() isn't working? WTF.
2016-04-21 20:52:32 -07:00
snipe 0a5e7214aa Fixed restore method 2016-04-21 20:27:03 -07:00
snipe 2284a0783f Improved user UI for user view 2016-04-21 20:26:56 -07:00
snipe aafa5597f2 Added history string 2016-04-21 19:45:49 -07:00
snipe 4c3dada8e4 More responsive UI for small screens 2016-04-21 19:45:42 -07:00
snipe c39e27cc5e Fixes #1955 - searching within locations 2016-04-19 20:23:04 -07:00
snipe 4efc30c63e Escape search query text 2016-04-19 20:22:37 -07:00
snipe b2e5fa84ea Prevent direct viewing of .env file if installed in a subdirectory 2016-04-19 19:44:09 -07:00
snipe 5c99f9da15 Change certificate icon to floppy disk icon 2016-04-19 19:42:16 -07:00
snipe 38551d53a9 Added zenhub badge 2016-04-19 15:50:57 -07:00
snipe 2ec44ae14a Updated translation strings with new purge text 2016-04-19 12:26:49 -07:00
snipe f2d883e711 Removed box header 2016-04-19 07:43:49 -07:00
snipe 13f85e82bb Fixes #1909 - allow 0 month depreciation 2016-04-19 07:39:54 -07:00
snipe 679a6a5522 Partial - add support for drag+drop reordering 2016-04-19 07:19:12 -07:00
snipe b72429a303 Suppress console log 2016-04-19 07:17:57 -07:00
snipe 3e84d66c80 Re-use settings to prevent 1001 queries 2016-04-19 06:11:20 -07:00
snipe c4ea4f80b1 Fixes #1693 - hide soft-deletes assets from asset model view 2016-04-19 04:55:16 -07:00
snipe 7c710e3fbe Updated kernel with new namespace 2016-04-19 04:36:36 -07:00
snipe 599066cbde Use error method to highlight errors in import console 2016-04-19 04:36:25 -07:00
snipe 49c09dd356 Added ability to purge soft-deletes from admin 2016-04-19 04:36:07 -07:00
snipe 78aa0cc378 Fixes #1918 - wrong link for status 2016-04-19 02:44:59 -07:00
snipe 7d5e9fb135 Updated travis with new cli commands 2016-04-19 02:30:59 -07:00
snipe 18869550a7 Fixed stray quotes 2016-04-19 02:28:54 -07:00
snipe 9de2725de0 More purge fixes 2016-04-19 01:38:11 -07:00
snipe a8ff632740 Fixes asset purge 2016-04-19 01:27:04 -07:00
snipe 74400eb9a1 Purge function to delete all soft-deleted items 2016-04-19 00:47:54 -07:00
snipe 4161a8af29 Change snipe-it commands to use common namespace 2016-04-19 00:47:32 -07:00
snipe e4b5d426db Set DB prefix in env 2016-04-19 00:47:12 -07:00
snipe f1ad5461d8 Feature: Artisan command to allow you to disable LDAP in case you lock yourself out. 2016-04-14 11:59:01 -07:00
snipe 65fe564774 Pull the acceptance tests. Again. :(
Giving up.
2016-04-13 05:20:40 -07:00
snipe 30b82f61ec I don't think we need all this for the login page 2016-04-13 05:01:13 -07:00
snipe 2026a91bde Remove < PHP 5.6, since Laravel 5.2 requires PHP 5.6 2016-04-13 04:31:28 -07:00
snipe 90a99429b3 Ugh, stupid indenting 2016-04-13 04:30:49 -07:00
snipe 1a2e545748 Configs. Again. 2016-04-13 04:30:13 -07:00
snipe d02423c1a5 Reverting url 2016-04-13 04:24:16 -07:00
snipe 3157a76e36 More poking and hoping. Travis is a piece of shit. 2016-04-13 04:11:38 -07:00
snipe 7236559b44 Try adding a defaul url to override the Webdriver "url is blank" bullshit 2016-04-13 04:07:03 -07:00
snipe 942b8d1b3c Put ORM back in 2016-04-13 03:56:44 -07:00
snipe 12e3d4647f Config URL is not found again. 2016-04-13 02:58:11 -07:00
snipe e094beea72 Hm, that didn't work 2016-04-13 02:50:56 -07:00
snipe c04754a17c https to http 2016-04-13 02:47:10 -07:00
snipe 0b71789274 Switched configs around a little 2016-04-13 02:41:55 -07:00
snipe 35cbf238a7 Yay, brand new error. 2016-04-13 02:25:45 -07:00
snipe 90b43a382f Try using the testing-ci version of phpunit.xml 2016-04-13 02:19:50 -07:00
snipe 49405b48a3 Reverted name removal for Accessory in factory 2016-04-13 02:19:29 -07:00
snipe 3d666b27e0 Add Asserts 2016-04-13 02:19:09 -07:00
snipe 79073e5f1a Remove constructor 2016-04-13 02:19:03 -07:00
snipe e59d19865d Maybe the names are what's breaking it? 2016-04-13 01:58:46 -07:00
snipe 20876a4502 Meh 2016-04-13 01:51:28 -07:00
snipe 468fb14274 Added ci config to _env 2016-04-13 01:23:47 -07:00
snipe eaa02ef7d3 More poking and hoping 2016-04-13 01:14:23 -07:00
snipe 62b3653e7c Fixed CI db stuff 2016-04-13 01:08:02 -07:00
snipe 91c9a08d29 Switch back to testing-ci 2016-04-13 01:01:03 -07:00
snipe 1eeb4d042a Sigh. 2016-04-13 00:56:43 -07:00
snipe 454d0daa25 This won't work either, but running out of ideas 2016-04-13 00:45:42 -07:00
snipe 1c6e4a74be Why the fuck not. 2016-04-13 00:35:28 -07:00
snipe 7083bb50ca Remove sqlite references (duh) 2016-04-12 23:56:13 -07:00
snipe 561bf038f7 Remove sqlite env var 2016-04-12 23:45:14 -07:00
snipe 4def8b7349 Try mysql for travis 2016-04-12 23:43:53 -07:00
snipe db83faeb49 Remove baseurl 2016-04-12 23:32:52 -07:00
snipe cf0a2051b0 Remove constructor 2016-04-12 22:53:38 -07:00
snipe f7d1415e33 Added SetUp back in :( 2016-04-12 22:49:07 -07:00
snipe aa4bb121ae Remove the putenv 2016-04-12 22:10:50 -07:00
snipe 1fb8f421a2 Add parent::createApplication(); 2016-04-12 22:00:21 -07:00
snipe a6a6edfeaa Updated travis.yml 2016-04-12 21:01:39 -07:00
snipe cbe0f8a9eb Split environments into configs 2016-04-12 21:00:20 -07:00
snipe cc057fe282 Reformatting URL in acceptance.yml 2016-04-12 20:48:37 -07:00
snipe 39c7439be6 Removed custom phantomJS stuff - it's 404ing 2016-04-12 20:21:53 -07:00
snipe f7b6276311 Updated test url 2016-04-12 20:21:39 -07:00
snipe cd0df27516 Comment edit 2016-04-12 19:24:02 -07:00
snipe 6a8883104d Fixed DB name in testing config 2016-04-12 19:23:40 -07:00
snipe b6fa3a2a89 Added todos, fixed ID casing 2016-04-07 17:23:52 -07:00
snipe 40aac1bf89 Fixed seeds 2016-04-07 17:15:41 -07:00
snipe 4b168e8cfa Fixes #1932 - disallow category delete if there are assets/accessories/etc 2016-04-07 17:15:30 -07:00
snipe d601db2090 Updated docs 2016-04-07 17:08:38 -07:00
snipe bf728da39d Updated to use 5.2 trans() instead of Lang::get for localization 2016-04-07 13:39:35 -07:00
snipe a62859dc6d Updated docblocks 2016-04-07 13:21:09 -07:00
snipe 95e4845176 Fix userlist for accessory checkout 2016-04-07 05:03:14 -07:00
snipe 0e6b8a8358 Switch to use trans from Lang::get for laravel 5.2 2016-04-07 02:51:57 -07:00
snipe 64d36a9e64 Fixes #1922 - sort by license name 2016-04-04 22:16:24 -07:00
snipe ecf9734105 Swtch env to just testing.
This won't work, but neither does anything else
2016-03-30 18:31:09 -07:00
snipe 2e7ddb75db Try diff block for testing (not testing-ci) 2016-03-30 15:56:53 -07:00
snipe 269944ecdf Try adding phantom as the browser 2016-03-30 15:47:29 -07:00
snipe 4a7b0c0d0f Updated docblocks 2016-03-28 22:51:49 -07:00
snipe 08c196872c Removed IP test in custom fields since we are using laravel's IP validation now 2016-03-28 21:53:36 -07:00
snipe 093e4bbb73 Updated translations 2016-03-28 21:50:00 -07:00
snipe 6f9bad1005 Use lightbox for images in asset file listing 2016-03-25 20:38:27 -07:00
snipe 90d4a8b2e3 Cleanup namespaces a bit 2016-03-25 19:26:22 -07:00
snipe e7405e8d89 Coding is still hard, apparently. 2016-03-25 18:51:44 -07:00
snipe a10da2e148 Fixes error loading consumables 2016-03-25 18:29:45 -07:00
snipe 3f97cc0137 Fixes the fucking "Assets Retired" thing AGAIN. 2016-03-25 18:22:25 -07:00
snipe 41384dc62f Fixes #1845 - remove ability for users to change their email and password 2016-03-25 18:20:57 -07:00
snipe f1558706ff Updated docblocks 2016-03-25 18:07:12 -07:00
snipe 46a76e2c55 More compact user code 2016-03-25 17:45:50 -07:00
snipe bd1cb921fc Nicer namespacing and lazy eager loading for 101 queries in location assets 2016-03-25 17:38:17 -07:00
snipe 2b74fd86cb Trying to fix backup script
This is still broken, but I will come back to it
2016-03-25 17:21:01 -07:00
snipe 95e2825716 A few more path fixes 2016-03-25 17:20:28 -07:00
snipe e60bda0563 Updated file paths for uploads 2016-03-25 17:12:31 -07:00
snipe bddb7fca23 Additional doc blocks, added private_uploads path 2016-03-25 15:50:08 -07:00
snipe 27543d16f6 Additional escaping 2016-03-25 15:24:12 -07:00
snipe f1bdaeaf95 Escaped input on listing page 2016-03-25 14:24:27 -07:00
snipe 34536f29e9 Updated url with my local env SSL 2016-03-25 06:54:48 -07:00
snipe 4b9dc430c4 Escape data in datatables 2016-03-25 06:50:24 -07:00
snipe 753a7333f1 If the settings table is empty, set a default 2016-03-25 05:39:08 -07:00
snipe a306574751 Check whether the login page even loads :( 2016-03-25 05:29:42 -07:00
snipe f902e3b8ce Another try fixing phantom 2016-03-25 05:21:45 -07:00
snipe 938e940366 Try to build phantom manually 2016-03-25 05:05:11 -07:00
snipe 5d3364c846 One more time 2016-03-25 04:54:01 -07:00
snipe 7c985ad495 Possible fix for travis (haha yeah right) 2016-03-25 04:48:26 -07:00
snipe fb84ba2878 Add color picker just to settings 2016-03-25 04:18:01 -07:00
snipe 82d6a4e025 Fixed Asset namespace 2016-03-25 04:16:32 -07:00
snipe 46e003ce75 Replaced readme 2016-03-25 04:03:28 -07:00
snipe eb95f5ca4f Cleanup js and CSS elixir stuff 2016-03-25 03:36:37 -07:00
snipe 7ec109c4d8 Fixed slug helper 2016-03-25 03:32:35 -07:00
snipe 99dee751f3 Updated menu color for readability 2016-03-25 02:07:35 -07:00
snipe aff133b5f1 Applied updates from PR for LDAP pagination 2016-03-25 01:38:10 -07:00
snipe bd334076ca Updated installer 2016-03-25 01:24:28 -07:00
snipe fe00b0e401 Version 3 - hold onto your butts 2016-03-25 01:18:05 -07:00
5612 changed files with 579498 additions and 95979 deletions
-37
View File
@@ -1,37 +0,0 @@
ls
pwd
cd app
ls
cd views/
cd backend/
ls
cd users/
ls
vi view.blade.php
ls -alF
cd
pwd
ls -alF
pwd
cd app
ls
cd views/
cd backend/
cd users/
ls
ls -alF
chown snipeitftp view.blade.php
sudo chown snipeitftp view.blade.php
pwd
ls
vi view.blade.php
set noswapfile
set nobackup
vi view.blade.php
touch delete.me
vi delete.me
ls
ls -alF
touch view.blade.php
touch index.blade.php
vi view.blade.php
+5
View File
@@ -0,0 +1,5 @@
.git
.dockerignore
app/storage/logs/*
app/storage/views/*
vendor/*
+77
View File
@@ -0,0 +1,77 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=production
APP_DEBUG=false
APP_KEY=ChangeMe
APP_URL=null
APP_TIMEZONE='UTC'
APP_LOCALE=en
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=null
DB_USERNAME=null
DB_PASSWORD=null
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER=smtp
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=YOURUSERNAME
MAIL_PASSWORD=YOURPASSWORD
MAIL_ENCRYPTION=null
MAIL_FROM_ADDR=you@example.com
MAIL_FROM_NAME=Snipe-IT
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
# This should be gd or imagick
# --------------------------------------------
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=false
COOKIE_NAME=snipeit_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET=null
AWS_KEY=null
AWS_REGION=null
AWS_BUCKET=null
# --------------------------------------------
# OPTIONAL: MISC
# --------------------------------------------
APP_LOG=single
APP_LOCKED=false
FILESYSTEM_DISK=local
APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1
+71
View File
@@ -0,0 +1,71 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing
APP_DEBUG=true
APP_KEY=ChangeMe
APP_URL=http://localhost:8000
APP_TIMEZONE='US/Pacific'
APP_LOCALE=en
FILESYSTEM_DISK=local
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=sqlite_testing
DB_HOST=localhost
DB_DATABASE=testing.sqlite
DB_USERNAME=null
DB_PASSWORD=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER=smtp
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=YOURUSERNAME
MAIL_PASSWORD=YOURPASSWORD
MAIL_ENCRYPTION=null
MAIL_FROM_ADDR=you@example.com
MAIL_FROM_NAME=Snipe-IT
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
# This should be gd or imagick
# --------------------------------------------
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET=null
AWS_KEY=null
AWS_REGION=null
AWS_BUCKET=null
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=false
COOKIE_NAME=snipeittest_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: APP LOG FORMAT
# --------------------------------------------
APP_LOG=single
+71
View File
@@ -0,0 +1,71 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing-ci
APP_DEBUG=true
APP_KEY=ChangeMe
APP_URL=http://localhost:8000
APP_TIMEZONE='US/Pacific'
APP_LOCALE=en
FILESYSTEM_DISK=local
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=snipeit_unit
DB_USERNAME=travis
DB_PASSWORD=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER=smtp
MAIL_HOST=email-smtp.us-west-2.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=YOURUSERNAME
MAIL_PASSWORD=YOURPASSWORD
MAIL_ENCRYPTION=null
MAIL_FROM_ADDR=you@example.com
MAIL_FROM_NAME=Snipe-IT
# --------------------------------------------
# REQUIRED: IMAGE LIBRARY
# This should be gd or imagick
# --------------------------------------------
IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET=null
AWS_KEY=null
AWS_REGION=null
AWS_BUCKET=null
# --------------------------------------------
# OPTIONAL: CACHE SETTINGS
# --------------------------------------------
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
# --------------------------------------------
# OPTIONAL: SESSION SETTINGS
# --------------------------------------------
SESSION_LIFETIME=12000
EXPIRE_ON_CLOSE=false
ENCRYPT=false
COOKIE_NAME=snipeittest_session
COOKIE_DOMAIN=null
SECURE_COOKIES=false
# --------------------------------------------
# OPTIONAL: APP LOG FORMAT
# --------------------------------------------
APP_LOG=single
+31
View File
@@ -0,0 +1,31 @@
#### Expected Behavior (or desired behavior if a feature request)
(what you expect to happen goes here)
-----
#### Actual Behavior
(what actually happens goes here)
-----
#### Please confirm you have done the following before posting your bug report:
- [ ] I have enabled debug mode
- [ ] I have read [checked the Common Issues page](http://docs.snipeitapp.com/common-issues.html)
-----
#### Please provide answers to these questions before posting your bug report:
- Version of Snipe-IT you're running
- What OS and web server you're running Snipe-IT on
- What method you used to install Snipe-IT (install.sh, manual installation, docker, etc)
- If you're getting an error in your browser, include that error
- What specific Snipe-IT page you're on, and what specific element you're interacting with to trigger the error
- If a stacktrace is provided in the error, include that too.
- Any errors that appear in your browser's error console.
- Confirm whether the error is [reproduceable on the demo](https://snipeitapp.com/demo).
- Include any additional information you can find in `app/storage/logs` and your webserver's logs.
- Include what you've done so far in the installation, and if you got any error messages along the way.
- Indicate whether or not you've manually edited any data directly in the database
+45 -14
View File
@@ -1,18 +1,49 @@
/bootstrap/compiled.php
/vendor
composer.phar
/node_modules
Homestead.yaml
Homestead.json
.env
tests/_output/*
.DS_Store
/app/config/database.php
/app/config/mail.php
/app/database/*.sqlite
/app/storage/meta/services.json
/app/config/*/mail.php
/app/config/*/database.php
/app/config/*/app.php
public/packages/*
public/uploads/models/*
public/uploads/avatars/*
/app/storage/views/*
/app/storage/logs/*
/app/storage/debugbar/
/bin/
public/uploads/suppliers/*
public/uploads/assets/*
public/uploads/users/*
public/uploads/*.gif
public/uploads/*.jpg
public/uploads/*.png
public/uploads/*.tif
public/uploads/*.svg
storage/app/private_uploads/users/*
phpDocumentor.phar
output
tests/_support/_generated/*
/bootstrap/compiled.php
composer.phar
app/config/database.php
app/config/mail.php
app/database/*.sqlite
app/storage/meta/services.json
app/config/*/mail.php
app/config/*/session.php
app/config/*/database.php
app/config/*/app.php
app/config/*/ldap.php
public/packages/*
storage/logs/*
storage/debugbar/
/bin/
.idea
crowdin.yaml
public/uploads/logo.gif
public/uploads/logo.svg
public/uploads/logo.png
.couscous
storage/dumps/*
tests/_data/scenarios
storage/laravel-backups
storage/private_uploads/users/*
+11
View File
@@ -0,0 +1,11 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
# Make sure .env files not not browseable if in a sub-directory.
<FilesMatch "\.env$">
Deny from all
</FilesMatch>
</IfModule>
Executable → Regular
+40 -16
View File
@@ -1,34 +1,58 @@
addons:
hosts:
- localhost
sudo: false
# see http://about.travis-ci.org/docs/user/languages/php/ for more hints
language: php
# list any PHP version you want to test against
php:
- 5.4
- 5.5
- 5.6
# optionally specify a list of environments, for example to test different RDBMS
env:
- DB=mysql
- 7.0
# execute any number of scripts before the test run, custom env's are available as variables
before_script:
- if [[ "$DB" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS snipeit_laravel;" -utravis; fi
- curl -s http://getcomposer.org/installer | php
- cp app/config/production/database.example.php app/config/database.php
- cp app/config/production/mail.example.php app/config/mail.php
- composer install --prefer-source --no-interaction --dev
- phantomjs --webdriver=4444 &
- sleep 10
- mysql -e "create database IF NOT EXISTS snipeit_unit;" -utravis
- composer self-update
- composer install -n --prefer-source
- cp .env.testing-ci .env
- chmod -R 777 storage
- php artisan migrate --database=mysql --force
- ./vendor/bin/codecept build
- php artisan key:generate
- php artisan migrate:install
- php artisan migrate --package cartalyst/sentry
- php artisan migrate
- php artisan db:seed
- php artisan db:seed --database=mysql --force
- php artisan snipeit:create-admin --first_name=Alison --last_name=Foobar --email=me@example.com --username=snipe --password=password
- php artisan serve --port=8000 --host=localhost &
- sleep 5
- pip install --user codecov
- sleep 5
# omitting "script:" will default to phpunit
# use the $DB env variable to determine the phpunit.xml to use
script: phpunit
# script: ./vendor/bin/codecept run --env testing-ci - broken :(
script: ./vendor/bin/codecept run unit --env testing-ci
#script: ./vendor/bin/codecept run
after_success:
- codecov
after_failure:
- cat tests/_output/AccessoriesCept.fail.html
- curl http://localhost:8000/login
# configure notifications (email, IRC, campfire etc)
notifications:
email: false
slack:
secure: vv9we1RxB9RsrMbomSdq6D7vz/okobw87pEkgIZjB+hj1QpQ2by90gsPsOa+NgsJEFaEP7e4KlT6SH8kK+zhbmuKaUd3d1//XdcancE22LZXi6tkiB5yuR/Jhhb1LLDqyGJTB4D92hMnnCPiUjpxNA3r437ttNeYRdYIEEP3drA=
webhooks:
urls:
- https://webhooks.gitter.im/e/5e136eb0c1965f3918d0
on_success: change # options: [always|never|change] default: always
on_failure: change # options: [always|never|change] default: always
on_start: false # default: false
-137
View File
@@ -1,137 +0,0 @@
### v0.3.11-alpha - Released Jul 19, 2014 07:16:53
#### This is a pre-release
### v0.3.10-alpha - Released Jul 17, 2014 07:54:10
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/89a8f3c277d2482b2cd04c4c5c582c9e507770f8">view</a> &bull; Fixes #183 - added employee number to users
* <a href="http://github.com/snipe/snipe-it/commit/a7b809cb91f49fb2c8eaecc67822fa155a0f20ce">view</a> &bull; Updated title/header for users, additional fixes for #151
* <a href="http://github.com/snipe/snipe-it/commit/5266d9a30a9663fa80ff764b25ff71726e5c4f4c">view</a> &bull; Fixed title tag for user list view
* <a href="http://github.com/snipe/snipe-it/commit/43485e1a51330ef585a65b469d7eb85ae7bde13a">view</a> &bull; Fixed language definition
* <a href="http://github.com/snipe/snipe-it/commit/6b5a552d95ff6f6d5567275b50fcd487fb793820">view</a> &bull; Fixed #186 - Bug with select box not retaining selections on edit screen
* <a href="http://github.com/snipe/snipe-it/commit/90eb883b671919ea360122c2bf44433995a12144">view</a> &bull; Fixed #187 - replaced dummy site name with site name from admin panel preferences
* <a href="http://github.com/snipe/snipe-it/commit/f22f23f21dc11d393854849580f0c1229cec9827">view</a> &bull; Fixed button label on forgotten password page
* <a href="http://github.com/snipe/snipe-it/commit/2b9494ed8271254f8f84e016f238d518e6109842">view</a> &bull; Fixed inconsistent password requirements across admin user creation, user profile and forgotten password
* <a href="http://github.com/snipe/snipe-it/commit/9dc40a3a9c161267fd8c88aacc1fbf536c1ec2de">view</a> &bull; Fixed a few CSS quirks
* <a href="http://github.com/snipe/snipe-it/commit/99003e126a8fd0ad9aaea5a550e0af5e306fc1bb">view</a> &bull; Fixed bug with edit (supplier_id), added requestable field for assets
* <a href="http://github.com/snipe/snipe-it/commit/21251b462308f2d783b83be1a331a0faf0813d16">view</a> &bull; Fixed #190, where depreciation on licenses would not be saved
* <a href="http://github.com/snipe/snipe-it/commit/89000440f344f766a31adc69718d7f66df235abf">view</a> &bull; Added admin ability to unsuspend locked accounts #changelog
* <a href="http://github.com/snipe/snipe-it/commit/e203fc516fadf6218f5ce87c070d0cdba9fca188">view</a> &bull; Fixes #194
### v0.3.9-alpha - Released Jul 03, 2014 04:08:38
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/2825bcb4310899e89ccbc73dfa8b59ade28018da">view</a> &bull; Fixed #179 - account page to show assets checked out to the logged in user
* <a href="http://github.com/snipe/snipe-it/commit/c782f29f5aae752a6246be9778d418df172dd4f6">view</a> &bull; Pulled account sub-nav into top menu to free up UI space. #changelog
* <a href="http://github.com/snipe/snipe-it/commit/fad2ec66fa9abe0b34baf16cce453a7e9fc9e4d4">view</a> &bull; More README fixes and refinement
### v0.3.8-alpha - Released Jun 27, 2014 11:28:22
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/3e7a9e45d1954531bbc3b73f2ed59dd16d59c657">view</a> &bull; Fixes PR #168 and #167
* <a href="http://github.com/snipe/snipe-it/commit/945cb3253f1349e30aafa4e7cb57bb507a2ea0cc">view</a> &bull; Fix #117
* <a href="http://github.com/snipe/snipe-it/commit/6f42b3045e2a65cdf98ec1038284cc2ecf01fa5d">view</a> &bull; Resolves #155
* <a href="http://github.com/snipe/snipe-it/commit/380417953b6b67a506f0cc395fd2dfb744cf26cd">view</a> &bull; Fixed missing string
* <a href="http://github.com/snipe/snipe-it/commit/b09aec67f1ab76ff0435a2e1e49b179c3d73bc12">view</a> &bull; Fixes #155
* <a href="http://github.com/snipe/snipe-it/commit/124acc89c4027e346daf54c62cb38b85586de870">view</a> &bull; Resolves #174
* <a href="http://github.com/snipe/snipe-it/commit/afabd2814205fdcd83b7bf9ce9095aa367b08311">view</a> &bull; Additional fixes for #167
* <a href="http://github.com/snipe/snipe-it/commit/a170efae2796314896d548d86b79d89d859c37d2">view</a> &bull; fix for #167
* <a href="http://github.com/snipe/snipe-it/commit/ec9eab81bfb3b35bfe7ad06008b26f19009e6638">view</a> &bull; Closes #177 - change log file added, needs refining
### v.0.3.5-alpha - Released Jun 20, 2014 04:23:09
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/d1499deecdff3c7a4235ffdfad5adbddc1a5098f">view</a> &bull; Provisions for strict mode, fixed license deletion bug
### v.0.3.4-alpha - Released Jun 20, 2014 12:27:59
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/08d05b481f6366ad48fcdce72a8df53755f5dee8">view</a> &bull; Fixes #158
### v.0.3.3-alpha - Released Jun 18, 2014 10:04:46
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/3518ab9f55f7992d6d4f886389d67b062a02f2d8">view</a> &bull; Fixes #139
* <a href="http://github.com/snipe/snipe-it/commit/ad9b1fc446ab15157502fe7c52ddbda455e3ea8f">view</a> &bull; Fixes #139
* <a href="http://github.com/snipe/snipe-it/commit/dfa5d1c64205b23c4c3d16190d1478da8aa0edbb">view</a> &bull; Fixes #136
* <a href="http://github.com/snipe/snipe-it/commit/9714178ce1fa1e2814389e4b6b82eb596a650084">view</a> &bull; Fixes #141
* <a href="http://github.com/snipe/snipe-it/commit/607484b29407718238571eb5269c9c27830338f7">view</a> &bull; Fixes #141 for mysql with strict mode enabled
* <a href="http://github.com/snipe/snipe-it/commit/cbc945299e7f67f5f10dfdc6a875e5c53ac8440a">view</a> &bull; Fixes #148
* <a href="http://github.com/snipe/snipe-it/commit/dc256583d410cb09253e30b075149c79fb4864e5">view</a> &bull; Fixes #144
* <a href="http://github.com/snipe/snipe-it/commit/610c405aa50118163ad5d26d43e4bf6c2456f624">view</a> &bull; More fixes for #151
### v.0.3.2-alpha - Released May 06, 2014 10:26:21
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/f4c5da57d0397877d90aa398267e59fcffee7b47">view</a> &bull; Fixed auth error when user isn't logged in
### v.0.3.1-alpha - Released May 06, 2014 06:48:09
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/efad5db082d1461ea26556fad2f1671a49dc1480">view</a> &bull; Fix for broken datatables in upgrading to v2.2
* <a href="http://github.com/snipe/snipe-it/commit/5690e9ce1f178486179ce6cdfb00ca417acd87dd">view</a> &bull; Fixed code indentation for Apache virtualhost example
* <a href="http://github.com/snipe/snipe-it/commit/67aba76d3f83c5f374c05fe07d52eebd81d13278">view</a> &bull; Fixing this change from #109 that somehow got reverted
* <a href="http://github.com/snipe/snipe-it/commit/06067fc19c0127fdcbb78541e7cdc8e77f5444ac">view</a> &bull; Fixed CSV rexport
### v0.3.0-alpha - Released Jan 29, 2014 02:28:31
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/d91d75abe4df19dd6cd54705ba9967295973ced0">view</a> &bull; Fixing JSON parse errors from #97
* <a href="http://github.com/snipe/snipe-it/commit/baab758377e117a86c3273dd1d6e03e66b02dc8b">view</a> &bull; Fixed language support
* <a href="http://github.com/snipe/snipe-it/commit/a678ec41714f5d7f77418b5933bc112aa67eae9c">view</a> &bull; Fixed Gravatar Hash
* <a href="http://github.com/snipe/snipe-it/commit/c08d672e4923b12972eae76d0699e6a301f911cd">view</a> &bull; Fixes mail config documentation
* <a href="http://github.com/snipe/snipe-it/commit/fba853a6a7a2f8166265cac2e99a526fd9b88c7b">view</a> &bull; Fixes composer formatting issues
* <a href="http://github.com/snipe/snipe-it/commit/c11510fdcac2b2de09ae9e241c846426bdf0b187">view</a> &bull; Removes sorting from actions column. Fixes #56
* <a href="http://github.com/snipe/snipe-it/commit/ae05f2701559a841cb8d9bc8767e6d7a56dcd93c">view</a> &bull; Fixed depreciation bug
* <a href="http://github.com/snipe/snipe-it/commit/d591c1ea0495de091eb0f71daa8572929096c897">view</a> &bull; Fixed bug where RTD = 1 instead of 0
* <a href="http://github.com/snipe/snipe-it/commit/e49420f62d26405b2fa0385f0ae7b3009b3beeaf">view</a> &bull; Fixed bug in depreciation display
* <a href="http://github.com/snipe/snipe-it/commit/1dc7fd1bdf8852fed6d886938f632c8ea69d4798">view</a> &bull; Fixed depreciation display on asset view
* <a href="http://github.com/snipe/snipe-it/commit/211a527ae176df667f6f8fbc95901c53a368d8e2">view</a> &bull; Fixed FK
* <a href="http://github.com/snipe/snipe-it/commit/aaebaa8d36158aafc61988a6370239e85f2e75e5">view</a> &bull; Bugfix to put custom title in the page title
* <a href="http://github.com/snipe/snipe-it/commit/194150bbf0493512018390d011e8d88d144e9763">view</a> &bull; Hacky shit to fix pagination weirdness - will come back to this
* <a href="http://github.com/snipe/snipe-it/commit/5fb649b59e76aa9db6e433ad8c9fc75b4b8d5fc2">view</a> &bull; Fixed error message layout
* <a href="http://github.com/snipe/snipe-it/commit/7bc9a53b133895206a3df230baca50d3879abbe5">view</a> &bull; Fixed error when user is invalid
* <a href="http://github.com/snipe/snipe-it/commit/82de635a75aba376209b741ce1ed4497b91e65e0">view</a> &bull; Fixed invalid seed data
* <a href="http://github.com/snipe/snipe-it/commit/b697c77cd85416ca502ec3bb28c990099c7faae3">view</a> &bull; Fixing error when no depreciation
* <a href="http://github.com/snipe/snipe-it/commit/432f44118f46381bdaa44daf61dfa35677aba0ee">view</a> &bull; Fixed FK in licenses model
* <a href="http://github.com/snipe/snipe-it/commit/4468cbd096e9990300240205baf7139eafbc423c">view</a> &bull; Fixes #112
* <a href="http://github.com/snipe/snipe-it/commit/cd62be0de03da071f344c8f66730cbc9e1475fb7">view</a> &bull; Minor div fix
* <a href="http://github.com/snipe/snipe-it/commit/9c369d72e1e7e29f3c205586c916b2f42b250047">view</a> &bull; Fixed typo
* <a href="http://github.com/snipe/snipe-it/commit/60d94eea04d1ebb93704e6a0d20621ff18708272">view</a> &bull; Changes serial to text area, allow new lines. Fixes #118
* <a href="http://github.com/snipe/snipe-it/commit/580590b4c0b4a2f76ef8edfe02de986267fc7395">view</a> &bull; Fixed === to == (PHP is loosely typed)
### v0.2.0-alpha - Released Nov 29, 2013 11:09:07
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/06cbd0723e415d81ea12aa48f2c37188741b2dbc">view</a> &bull; Fixes #93
* <a href="http://github.com/snipe/snipe-it/commit/e305099b45401c871f16fec23c200080830fcd5d">view</a> &bull; Fixed model view
* <a href="http://github.com/snipe/snipe-it/commit/7003eff42ca0e0ea2b9070187c0afd8ba1a8d8b0">view</a> &bull; More fixes for #88
* <a href="http://github.com/snipe/snipe-it/commit/567f395afaa19335671f366ce889630426f33273">view</a> &bull; More fixes for #88
* <a href="http://github.com/snipe/snipe-it/commit/02f1977d301cd449aa806e02e8a829516d436ef7">view</a> &bull; Fixed error message
* <a href="http://github.com/snipe/snipe-it/commit/11c657ffa4c3bdd01cd04b81d01980b2d795107c">view</a> &bull; Fixes #36
### v0.1.2-alpha - Released Nov 29, 2013 02:59:05
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/b1aa67ddb72158513f0a706996c8c1f5b3609aa5">view</a> &bull; Fixes #69
* <a href="http://github.com/snipe/snipe-it/commit/aa38d83ba6369215451d905e599492214e9f4b8b">view</a> &bull; Fixes #63 and #70
* <a href="http://github.com/snipe/snipe-it/commit/65cd28aad3903e11879e01faba382454dec7e75c">view</a> &bull; Fixes #14
* <a href="http://github.com/snipe/snipe-it/commit/6552401fd869fd285aef5e217438f4f055b53ab6">view</a> &bull; Fixes #77
* <a href="http://github.com/snipe/snipe-it/commit/012a889444fa25b174a5fb2c67e89c8c5fcf09aa">view</a> &bull; Corrected license seat count associated with license. Fixes #75
* <a href="http://github.com/snipe/snipe-it/commit/9e189aa309750c221c27352f35e2ca1f5fab9173">view</a> &bull; Fixes #80, also prevents the user from checking out an asset that is undeployable, etc
* <a href="http://github.com/snipe/snipe-it/commit/8680d98bc36bffa08f87020300b315d26be09928">view</a> &bull; Fixed status display bug
* <a href="http://github.com/snipe/snipe-it/commit/4fcdf72ab6505625f244a6e6ee8683204fb81ccd">view</a> &bull; Responsive design bug fixes, placeholder code for #64 (commented out)
* <a href="http://github.com/snipe/snipe-it/commit/d9a37f38228d55bb6265efc626e3ab7919013362">view</a> &bull; Fixes #88
* <a href="http://github.com/snipe/snipe-it/commit/5858bfb99b2144fbc805ec62cc90e6aaaf019f77">view</a> &bull; Fixed language file paths caused by #88
* <a href="http://github.com/snipe/snipe-it/commit/9f7cbc8a4f01ddf2596e831f658c9a8c321b2f46">view</a> &bull; Another fix related to #88, also accounts for users with invalid location_ids
* <a href="http://github.com/snipe/snipe-it/commit/f0f07b578b2439a627e5e946df0849d88d8526cf">view</a> &bull; Fixing pivot for users
* <a href="http://github.com/snipe/snipe-it/commit/9fa826b2e77ce22d25a8b3094bc825802d25be85">view</a> &bull; Fixed assigned to id
### v0.1.1-alpha - Released Nov 27, 2013 12:11:00
#### This is a pre-release
* <a href="http://github.com/snipe/snipe-it/commit/1527b88fd671a20c879c9b2061ae95f3b386ba27">view</a> &bull; Fixes #61
* <a href="http://github.com/snipe/snipe-it/commit/4c0af1eae1031c2630f6e29cc73f8a9dfac1081c">view</a> &bull; Fixed typo causing failure with mysql strict
* <a href="http://github.com/snipe/snipe-it/commit/0e3bcfecd05a39bfea6fc7ba11cb24d9d49e6d86">view</a> &bull; Should be final fixes for mysql strict mode
-25
View File
@@ -1,25 +0,0 @@
# Contribution Guidelines
Please submit all issues and pull requests to the [snipe/snipe-it](http://github.com/snipe/snipe-it) repository in the `develop` branch!
**As you're working on bug-fixes or features, please break them out into their own feature branches and open the pull request against your feature branch**. It makes it _much_ easier to decipher down the road, as you open multiple pull requests over time, and makes it much easier for me to approve pull requests quickly.
If you don't have a feature in mind, but would like to contribute back to the project, check out the [open issues](https://github.com/snipe/snipe-it/issues?state=open) and see if there are any you can tackle.
-----
## Translations!
If you're not great at PHP and you still want to help, consider contributing some translation files (assuming, of course, that you are fluent in another language.)
To do so:
* fork the develop branch
* create a new branch on your new fork (something like `translations/french`)
* copy the `en` directory and name it according to the [two-letter ISO 639-1 code](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
* translate the strings
* submit a pull request!
**If you've translated Snipe IT into another language already for your own usage, please consider contributing those translation files back to the project so that everyone can benefit.**
Thanks!
+93
View File
@@ -0,0 +1,93 @@
FROM ubuntu:trusty
MAINTAINER Brady Wetherington <uberbrady@gmail.com>
RUN apt-get update && apt-get install -y \
apache2-bin \
libapache2-mod-php5 \
php5-curl \
php5-ldap \
php5-mysql \
php5-mcrypt \
php5-gd \
patch \
curl \
vim \
git \
mysql-client
RUN php5enmod mcrypt
RUN php5enmod gd
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php5/apache2/php.ini
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php5/cli/php.ini
RUN useradd --uid 1000 --gid 50 docker
RUN echo export APACHE_RUN_USER=docker >> /etc/apache2/envvars
RUN echo export APACHE_RUN_GROUP=staff >> /etc/apache2/envvars
COPY docker/000-default.conf /etc/apache2/sites-enabled/000-default.conf
#SSL
RUN mkdir -p /var/lib/snipeit/ssl
COPY docker/001-default-ssl.conf /etc/apache2/sites-enabled/001-default-ssl.conf
#COPY docker/001-default-ssl.conf /etc/apache2/sites-available/001-default-ssl.conf
RUN a2enmod ssl
#RUN a2ensite 001-default-ssl.conf
COPY . /var/www/html
RUN a2enmod rewrite
############ INITIAL APPLICATION SETUP #####################
WORKDIR /var/www/html
#Append to bootstrap file (less brittle than 'patch')
# RUN sed -i 's/return $app;/$env="production";\nreturn $app;/' bootstrap/start.php
#copy all configuration files
# COPY docker/*.php /var/www/html/app/config/production/
COPY docker/docker.env /var/www/html/.env
RUN chown -R docker /var/www/html
RUN \
rm -r "/var/www/html/storage/private_uploads" && ln -fs "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads" && \
mkdir -p "/var/www/html/public/uploads" && \
rm -rf "/var/www/html/public/uploads/avatars" && ln -fs "/var/lib/snipeit/data/uploads/avatars" "/var/www/html/public/uploads/avatars" && \
rm -rf "/var/www/html/public/uploads/models" && ln -fs "/var/lib/snipeit/data/uploads/models" "/var/www/html/public/uploads/models" && \
rm -rf "/var/www/html/public/uploads/suppliers" && ln -fs "/var/lib/snipeit/data/uploads/suppliers" "/var/www/html/public/uploads/suppliers" && \
rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups"
############## DEPENDENCIES via COMPOSER ###################
#global install of composer
RUN cd /tmp;curl -sS https://getcomposer.org/installer | php;mv /tmp/composer.phar /usr/local/bin/composer
# Get dependencies
RUN cd /var/www/html;composer install
############### APPLICATION INSTALL/INIT #################
#RUN php artisan app:install
# too interactive! Try something else
#COPY docker/app_install.exp /tmp/app_install.exp
#RUN chmod +x /tmp/app_install.exp
#RUN /tmp/app_install.exp
############### DATA VOLUME #################
VOLUME [/var/lib/snipeit]
##### START SERVER
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 80
EXPOSE 443
Executable → Regular
+23 -33
View File
@@ -1,65 +1,55 @@
[![Click here to lend your support to: Snipe IT - Free Open Source Asset Management System and make a donation at pledgie.com](https://pledgie.com/campaigns/22899.png?skin_name=chrome)](https://pledgie.com/campaigns/22899) [![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&title=Ready)](http://waffle.io/snipe/snipe-it) [![ProjectStatus](http://stillmaintained.com/snipe/snipe-it.png)](http://stillmaintained.com/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.png)](https://crowdin.com/project/snipe-it)
[![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&amp;title=Ready+for+development)](http://waffle.io/snipe/snipe-it) [![Maintenance](https://img.shields.io/maintenance/yes/2016.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&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
## Snipe-IT - Asset Management For the Rest of Us
## Snipe-IT - Open Source Asset Management System
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
It is built on [Laravel 4.1](http://laravel.com) and uses the [Sentry 2](https://github.com/cartalyst/sentry) package.
It is built on [Laravel 5.2](http://laravel.com).
This project is being actively developed and we're [releasing quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](http://snipeitapp.com/demo.php).)
Snipe-IT is actively developed and we're [releasing quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
__This is web-based software__. This means there there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows.
__This is web-based software__. This means there there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
-----
### Documentation & Installation
__Installation and configuration documentation for this project has been moved to http://docs.snipeitapp.com.__ This provides a more easily navigated, organized view of the documentation, and is based off of the [documentation branch](https://github.com/snipe/snipe-it/tree/documentation) in this repo. Contributions and bugfixes to the documentation are always welcome!
### Installation
We'll be adding a long-overdue user's manual soon as well.
For instructions on installing and configuring Snipe-IT on your server, check out the [installation manual](https://snipe-it.readme.io/docs). (Please see the [requirements documentation](https://snipe-it.readme.io/docs/requirements) for full requirements.)
__To deploy on Ubuntu using Ansible and Vagrant, be sure to check out the [Snipe-IT Installation scripts](https://github.com/GR360RY/snipeit-ansible) created by [@GR360RY](https://github.com/GR360RY/).__
If you're having trouble with the installation, please check the [Common Issues](https://snipe-it.readme.io/docs/common-issues) and [Getting Help](https://snipe-it.readme.io/docs/getting-help) documentation, and search this repository's open *and* closed issues for help.
-----
### User's Manual
For help using Snipe-IT, check out the [user's manual](https://snipe-it-manual.readme.io/docs).
-----
### Bug Reports & Feature Requests
Feel free to check out the [GitHub Issues for this project](https://github.com/snipe/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open and closed) to see if your question hasn't already been answered before opening a new issue.
We use Waffle.io to help better communicate our roadmap with users. Our [project page there](http://waffle.io/snipe/snipe-it) will show you the backlog, what's ready to be worked on, what's in progress, and what's completed.
[![Stories in Ready](https://badge.waffle.io/snipe/snipe-it.png?label=ready&title=Ready)](http://waffle.io/snipe/snipe-it)
-----
### Upgrading
Please see the [upgrading documentation](https://snipe-it.readme.io/docs/upgrading) for instructions on upgrading Snipe-IT.
------
### Announcement List
To be notified of important news (such as new releases, security advisories, etc), [sign up for our list](http://eepurl.com/XyZKz). We'll never sell or give away your info, and we'll only email you when it's important.
------
### Translations!
If you're not a coder but want to give back to the project and you're fluent in other languages, consider helping out with the translations. We use [CrowdIn](https://crowdin.com) to manage translations, and it makes it super-simple for you to add translations to the project without messing with code. Check out [the Snipe-IT CrowdIn translation project here](https://crowdin.com/project/snipe-it/).
We currently have English and Spanish completed, and are looking for lots more!
-----
## Requirements
- PHP 5.4 or later
- MCrypt PHP Extension
- Fileinfo Extension
And _one_ of the following image libraries (for QR codes, asset model image and user avatar image uploads).
- GD Library (>=2.0) … or …
- Imagick PHP extension (>=6.3.8)
Please see the [translations documentation](https://snipe-it.readme.io/docs/translations) for information about available languages and how to add translations to Snipe-IT.
-----
## Important Notes on Updating
### Contributing
Whenever you pull down a new version from master or develop, when you grab the [latest official release](https://github.com/snipe/snipe-it/releases), make sure to run the following commands via command line:
Please see the documentation on [contributing and developing for Snipe-IT](https://snipe-it.readme.io/docs/contributing).
php composer.phar dump-autoload
php artisan migrate
Forgetting to do this can mean your DB might end up out of sync with the new files you just pulled, or you may have some funky cached autoloader values. It's a good idea to get into the habit of running these every time you pull anything new down. If there are no database changes to migrate, it won't hurt anything to run migrations anyway.
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.
+463
View File
@@ -0,0 +1,463 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Models\Location;
use App\Models\Category;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\Asset;
use App\Models\Manufacturer;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Console\Command;
use League\Csv\Reader;
class AssetImportCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:asset-import';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import Assets from CSV';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$filename = $this->argument('filename');
if (!$this->option('testrun')=='true') {
$this->comment('======= Importing Assets from '.$filename.' =========');
} else {
$this->comment('====== TEST ONLY Asset Import for '.$filename.' ====');
$this->comment('============== NO DATA WILL BE WRITTEN ==============');
}
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$csv = Reader::createFromPath($this->argument('filename'));
$csv->setNewline("\r\n");
$csv->setOffset(1);
$duplicates = '';
// Loop through the records
$nbInsert = $csv->each(function ($row) use ($duplicates) {
$status_id = 1;
// Let's just map some of these entries to more user friendly words
// User's name
if (array_key_exists('0', $row)) {
$user_name = trim($row[0]);
} else {
$user_name = '';
}
// User's email
if (array_key_exists('1', $row)) {
$user_email = trim($row[1]);
} else {
$user_email = '';
}
// User's email
if (array_key_exists('2', $row)) {
$user_username = trim($row[2]);
} else {
$user_username = '';
}
// Asset Name
if (array_key_exists('3', $row)) {
$user_asset_asset_name = trim($row[3]);
} else {
$user_asset_asset_name = '';
}
// Asset Category
if (array_key_exists('4', $row)) {
$user_asset_category = trim($row[4]);
} else {
$user_asset_category = '';
}
// Asset Name
if (array_key_exists('5', $row)) {
$user_asset_name = trim($row[5]);
} else {
$user_asset_name = '';
}
// Asset Manufacturer
if (array_key_exists('6', $row)) {
$user_asset_mfgr = trim($row[6]);
} else {
$user_asset_mfgr = '';
}
// Asset model number
if (array_key_exists('7', $row)) {
$user_asset_modelno = trim($row[7]);
} else {
$user_asset_modelno = '';
}
// Asset serial number
if (array_key_exists('8', $row)) {
$user_asset_serial = trim($row[8]);
} else {
$user_asset_serial = '';
}
// Asset tag
if (array_key_exists('9', $row)) {
$user_asset_tag = trim($row[9]);
} else {
$user_asset_tag = '';
}
// Asset location
if (array_key_exists('10', $row)) {
$user_asset_location = trim($row[10]);
} else {
$user_asset_location = '';
}
// Asset notes
if (array_key_exists('11', $row)) {
$user_asset_notes = trim($row[11]);
} else {
$user_asset_notes = '';
}
// Asset purchase date
if (array_key_exists('12', $row)) {
if ($row[12]!='') {
$user_asset_purchase_date = date("Y-m-d 00:00:01", strtotime($row[12]));
} else {
$user_asset_purchase_date = '';
}
} else {
$user_asset_purchase_date = '';
}
// Asset purchase cost
if (array_key_exists('13', $row)) {
if ($row[13]!='') {
$user_asset_purchase_cost = trim($row[13]);
} else {
$user_asset_purchase_cost = '';
}
} else {
$user_asset_purchase_cost = '';
}
// Asset Company Name
if (array_key_exists('14', $row)) {
if ($row[14]!='') {
$user_asset_company_name = trim($row[14]);
} else {
$user_asset_company_name= '';
}
} else {
$user_asset_company_name = '';
}
// A number was given instead of a name
if (is_numeric($user_name)) {
$this->comment('User '.$user_name.' is not a name - assume this user already exists');
$user_username = '';
$first_name = '';
$last_name = '';
// No name was given
} elseif ($user_name=='') {
$this->comment('No user data provided - skipping user creation, just adding asset');
$first_name = '';
$last_name = '';
//$user_username = '';
} else {
$user_email_array = User::generateFormattedNameFromFullName($this->option('email_format'), $user_name);
$first_name = $user_email_array['first_name'];
$last_name = $user_email_array['last_name'];
if ($user_email=='') {
$user_email = $user_email_array['username'].'@'.config('app.domain');
}
if ($user_username=='') {
if ($this->option('username_format')=='email') {
$user_username = $user_email;
} else {
$user_name_array = User::generateFormattedNameFromFullName($this->option('username_format'), $user_name);
$user_username = $user_name_array['username'];
}
}
}
$this->comment('Full Name: '.$user_name);
$this->comment('First Name: '.$first_name);
$this->comment('Last Name: '.$last_name);
$this->comment('Username: '.$user_username);
$this->comment('Email: '.$user_email);
$this->comment('Category Name: '.$user_asset_category);
$this->comment('Item: '.$user_asset_name);
$this->comment('Manufacturer ID: '.$user_asset_mfgr);
$this->comment('Model No: '.$user_asset_modelno);
$this->comment('Serial No: '.$user_asset_serial);
$this->comment('Asset Tag: '.$user_asset_tag);
$this->comment('Location: '.$user_asset_location);
$this->comment('Purchase Date: '.$user_asset_purchase_date);
$this->comment('Purchase Cost: '.$user_asset_purchase_cost);
$this->comment('Notes: '.$user_asset_notes);
$this->comment('Company Name: '.$user_asset_company_name);
$this->comment('------------- Action Summary ----------------');
if ($user_username!='') {
if ($user = User::MatchEmailOrUsername($user_username, $user_email)
->whereNotNull('username')->first()) {
$this->comment('User '.$user_username.' already exists');
} else {
$user = new \App\Models\User;
$password = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $user_username;
$user->email = $user_email;
$user->permissions = '{user":1}';
$user->password = bcrypt($password);
$user->activated = 1;
if ($user->save()) {
$this->comment('User '.$first_name.' created');
} else {
$this->error('ERROR CREATING User '.$first_name.' '.$last_name);
$this->error($user->getErrors());
}
}
} else {
$user = new User;
}
// Check for the location match and create it if it doesn't exist
if ($location = Location::where('name', e($user_asset_location))->first()) {
$this->comment('Location '.$user_asset_location.' already exists');
} else {
$location = new Location();
if ($user_asset_location!='') {
$location->name = e($user_asset_location);
$location->address = '';
$location->city = '';
$location->state = '';
$location->country = '';
$location->user_id = 1;
if (!$this->option('testrun')=='true') {
if ($location->save()) {
$this->comment('Location '.$user_asset_location.' was created');
} else {
$this->error('Something went wrong! Location '.$user_asset_location.' was NOT created');
$this->error($location->getErrors());
}
} else {
$this->comment('Location '.$user_asset_location.' was (not) created - test run only');
}
} else {
$this->comment('No location given, so none created.');
}
}
if (e($user_asset_category)=='') {
$category_name = 'Unnamed Category';
} else {
$category_name = e($user_asset_category);
}
// Check for the category match and create it if it doesn't exist
if ($category = Category::where('name', e($category_name))->where('category_type', 'asset')->first()) {
$this->comment('Category '.$category_name.' already exists');
} else {
$category = new Category();
$category->name = e($category_name);
$category->category_type = 'asset';
$category->user_id = 1;
if ($category->save()) {
$this->comment('Category '.$user_asset_category.' was created');
} else {
$this->error('Something went wrong! Category '.$user_asset_category.' was NOT created');
$this->error($category->getErrors());
}
}
// Check for the manufacturer match and create it if it doesn't exist
if ($manufacturer = Manufacturer::where('name', e($user_asset_mfgr))->first()) {
$this->comment('Manufacturer '.$user_asset_mfgr.' already exists');
} else {
$manufacturer = new Manufacturer();
$manufacturer->name = e($user_asset_mfgr);
$manufacturer->user_id = 1;
if ($manufacturer->save()) {
$this->comment('Manufacturer '.$user_asset_mfgr.' was created');
} else {
$this->error('Something went wrong! Manufacturer '.$user_asset_mfgr.' was NOT created: '. $manufacturer->getErrors()->first());
}
}
// Check for the asset model match and create it if it doesn't exist
if ($asset_model = AssetModel::where('name', e($user_asset_name))->where('modelno', e($user_asset_modelno))->where('category_id', $category->id)->where('manufacturer_id', $manufacturer->id)->first()) {
$this->comment('The Asset Model '.$user_asset_name.' with model number '.$user_asset_modelno.' already exists');
} else {
$asset_model = new AssetModel();
$asset_model->name = e($user_asset_name);
$asset_model->manufacturer_id = $manufacturer->id;
$asset_model->modelno = e($user_asset_modelno);
$asset_model->category_id = $category->id;
$asset_model->user_id = 1;
if ($asset_model->save()) {
$this->comment('Asset Model '.$user_asset_name.' with model number '.$user_asset_modelno.' was created');
} else {
$this->error('Something went wrong! Asset Model '.$user_asset_name.' was NOT created: '.$asset_model->getErrors()->first());
}
}
// Check for the asset company match and create it if it doesn't exist
if ($user_asset_company_name!='') {
if ($company = Company::where('name', e($user_asset_company_name))->first()) {
$this->comment('Company '.$user_asset_company_name.' already exists');
} else {
$company = new Company();
$company->name = e($user_asset_company_name);
if ($company->save()) {
$this->comment('Company '.$user_asset_company_name.' was created');
} else {
$this->error('Something went wrong! Company '.$user_asset_company_name.' was NOT created: '.$company->getErrors()->first());
}
}
} else {
$company = new Company();
}
// Check for the asset match and create it if it doesn't exist
if ($asset = Asset::where('asset_tag', e($user_asset_tag))->first()) {
$this->comment('The Asset with asset tag '.$user_asset_tag.' already exists');
} else {
$asset = new Asset();
$asset->name = e($user_asset_asset_name);
if ($user_asset_purchase_date!='') {
$asset->purchase_date = $user_asset_purchase_date;
} else {
$asset->purchase_date = null;
}
if ($user_asset_purchase_cost!='') {
$asset->purchase_cost = ParseFloat(e($user_asset_purchase_cost));
} else {
$asset->purchase_cost = 0.00;
}
$asset->serial = e($user_asset_serial);
$asset->asset_tag = e($user_asset_tag);
$asset->model_id = $asset_model->id;
$asset->assigned_to = $user->id;
$asset->rtd_location_id = $location->id;
$asset->user_id = 1;
$asset->status_id = $status_id;
$asset->company_id = $company->id;
if ($user_asset_purchase_date!='') {
$asset->purchase_date = $user_asset_purchase_date;
} else {
$asset->purchase_date = null;
}
$asset->notes = e($user_asset_notes);
if ($asset->save()) {
$this->comment('Asset '.$user_asset_name.' with serial number '.$user_asset_serial.' was created');
} else {
$this->error('Something went wrong! Asset '.$user_asset_name.' was NOT created: '.$asset->getErrors()->first());
}
}
$this->comment('=====================================');
return true;
});
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('filename', InputArgument::REQUIRED, 'File for the CSV import.'),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('email_format', null, InputOption::VALUE_REQUIRED, 'The format of the email addresses that should be generated. Options are firstname.lastname, firstname, filastname', null),
array('username_format', null, InputOption::VALUE_REQUIRED, 'The format of the username that should be generated. Options are firstname.lastname, firstname, filastname, email', null),
array('testrun', null, InputOption::VALUE_REQUIRED, 'Test the output without writing to the database or not.', null),
);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CreateAdmin extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create an admin user via command line.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$first_name = $this->option('first_name');
$last_name = $this->option('last_name');
$username = $this->option('username');
$email = $this->option('email');
$password = $this->option('password');
$show_in_list = $this->argument('show_in_list');
if (($first_name=='') || ($last_name=='') || ($username=='') || ($email=='') || ($password=='')) {
$this->info('ERROR: All fields are required.');
} else {
$user = new \App\Models\User;
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $username;
$user->email = $email;
$user->permissions = '{"admin":1,"user":1,"superuser":1,"reports.view":1, "licenses.keys":1}';
$user->password = bcrypt($password);
$user->activated = 1;
if ($show_in_list == 'false') {
$user->show_in_list = 0;
}
if ($user->save()) {
$this->info('New user created');
$user->groups()->attach(1);
} else {
$this->info('Admin user was not created');
$errors = $user->getErrors();
foreach ($errors->all() as $error) {
$this->info('ERROR:'. $error);
}
}
}
}
// protected function getArguments()
// {
// return array(
// array('username', InputArgument::REQUIRED, 'Username'),
// );
// }
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Setting;
class DisableLDAP extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:ldap-disable';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This is a rescue command that can be used to turn off LDAP settings in the event that you managed to lock yourself out using bad LDAP settings.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nThis will disable LDAP support. You will not be able \nto login with an account that does not exist \nlocally in the Snipe-IT local database. \n****************************************************\n\nDo you wish to continue? [y|N]")) {
$setting = Setting::first();
$setting->ldap_enabled = 0;
if ($setting->save()) {
$this->info('LDAP has been set to disabled.');
} else {
$this->info('Unable to disable LDAP.');
}
} else {
$this->info('Canceled. No actions taken.');
}
}
}
@@ -0,0 +1,383 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use League\Csv\Reader;
use App\Models\User;
use App\Models\Supplier;
use App\Models\License;
use App\Models\LicenseSeat;
class LicenseImportCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:license-import';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import Licenses from CSV';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$filename = $this->argument('filename');
if (!$this->option('testrun')=='true') {
$this->comment('======= Importing Licenses from '.$filename.' =========');
} else {
$this->comment('====== TEST ONLY License Import for '.$filename.' ====');
$this->comment('============== NO DATA WILL BE WRITTEN ==============');
}
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$csv = Reader::createFromPath($this->argument('filename'));
$csv->setNewline("\r\n");
$csv->setOffset(1);
$duplicates = '';
// Loop through the records
$nbInsert = $csv->each(function ($row) use ($duplicates) {
$status_id = 1;
// Let's just map some of these entries to more user friendly words
if (array_key_exists('0', $row)) {
$user_name = trim($row[0]);
} else {
$user_name = '';
}
if (array_key_exists('1', $row)) {
$user_email = trim($row[1]);
} else {
$user_email = '';
}
if (array_key_exists('2', $row)) {
$user_username = trim($row[2]);
} else {
$user_username = '';
}
if (array_key_exists('3', $row)) {
$user_license_name = trim($row[3]);
} else {
$user_license_name = '';
}
if (array_key_exists('4', $row)) {
$user_license_serial = trim($row[4]);
} else {
$user_license_serial = '';
}
if (array_key_exists('5', $row)) {
$user_licensed_to_name = trim($row[5]);
} else {
$user_licensed_to_name = '';
}
if (array_key_exists('6', $row)) {
$user_licensed_to_email = trim($row[6]);
} else {
$user_licensed_to_email = '';
}
if (array_key_exists('7', $row)) {
$user_license_seats = trim($row[7]);
} else {
$user_license_seats = '';
}
if (array_key_exists('8', $row)) {
$user_license_reassignable = trim($row[8]);
if ($user_license_reassignable!='') {
if ((strtolower($user_license_reassignable)=='yes') || (strtolower($user_license_reassignable)=='true') || ($user_license_reassignable=='1')) {
$user_license_reassignable = 1;
}
} else {
$user_license_reassignable = 0;
}
} else {
$user_license_reassignable = 0;
}
if (array_key_exists('9', $row)) {
$user_license_supplier = trim($row[9]);
} else {
$user_license_supplier = '';
}
if (array_key_exists('10', $row)) {
$user_license_maintained = trim($row[10]);
if ($user_license_maintained!='') {
if ((strtolower($user_license_maintained)=='yes') || (strtolower($user_license_maintained)=='true') || ($user_license_maintained=='1')) {
$user_license_maintained = 1;
}
} else {
$user_license_maintained = 0;
}
} else {
$user_license_maintained = '';
}
if (array_key_exists('11', $row)) {
$user_license_notes = trim($row[11]);
} else {
$user_license_notes = '';
}
if (array_key_exists('12', $row)) {
if ($row[12]!='') {
$user_license_purchase_date = date("Y-m-d 00:00:01", strtotime($row[12]));
} else {
$user_license_purchase_date = '';
}
} else {
$user_license_purchase_date = 0;
}
// A number was given instead of a name
if (is_numeric($user_name)) {
$this->comment('User '.$user_name.' is not a name - assume this user already exists');
$user_username = '';
// No name was given
} elseif ($user_name=='') {
$this->comment('No user data provided - skipping user creation, just adding license');
$first_name = '';
$last_name = '';
$user_username = '';
} else {
$name = explode(" ", $user_name);
$first_name = $name[0];
$email_last_name = '';
$email_prefix = $first_name;
if (!array_key_exists(1, $name)) {
$last_name='';
$email_last_name = $last_name;
$email_prefix = $first_name;
} else {
$last_name = str_replace($first_name, '', $user_name);
if ($this->option('email_format')=='filastname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name[0].$email_last_name;
} elseif ($this->option('email_format')=='firstname.lastname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name.'.'.$email_last_name;
} elseif ($this->option('email_format')=='firstname') {
$email_last_name.=str_replace(' ', '', $last_name);
$email_prefix = $first_name;
}
}
$user_username = $email_prefix;
// Generate an email based on their name if no email address is given
if ($user_email=='') {
if ($first_name=='Unknown') {
$status_id = 7;
}
$email = strtolower($email_prefix).'@'.$this->option('domain');
$user_email = str_replace("'", '', $email);
}
}
$this->comment('Full Name: '.$user_name);
$this->comment('First Name: '.$first_name);
$this->comment('Last Name: '.$last_name);
$this->comment('Username: '.$user_username);
$this->comment('Email: '.$user_email);
$this->comment('License Name: '.$user_license_name);
$this->comment('Serial No: '.$user_license_serial);
$this->comment('Licensed To Name: '.$user_licensed_to_name);
$this->comment('Licensed To Email: '.$user_licensed_to_email);
$this->comment('Seats: '.$user_license_seats);
$this->comment('Reassignable: '.$user_license_reassignable);
$this->comment('Supplier: '.$user_license_supplier);
$this->comment('Maintained: '.$user_license_maintained);
$this->comment('Notes: '.$user_license_notes);
$this->comment('Purchase Date: '.$user_license_purchase_date);
$this->comment('------------- Action Summary ----------------');
if ($user_username!='') {
if ($user = User::where('username', $user_username)->whereNotNull('username')->first()) {
$this->comment('User '.$user_username.' already exists');
} else {
$user = new \App\Models\User;
$password = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $user_username;
$user->email = $user_email;
$user->permissions = '{user":1}';
$user->password = bcrypt($password);
$user->activated = 1;
if ($user->save()) {
$this->comment('User '.$first_name.' created');
} else {
$this->error('ERROR CREATING User '.$first_name.' '.$last_name);
$this->error($user->getErrors());
}
$this->comment('User '.$first_name.' created');
}
} else {
$user = new User;
$user->user_id = null;
}
// Check for the supplier match and create it if it doesn't exist
if ($supplier = Supplier::where('name', $user_license_supplier)->first()) {
$this->comment('Supplier '.$user_license_supplier.' already exists');
} else {
$supplier = new Supplier();
$supplier->name = e($user_license_supplier);
$supplier->user_id = 1;
if ($supplier->save()) {
$this->comment('Supplier '.$user_license_supplier.' was created');
} else {
$this->comment('Something went wrong! Supplier '.$user_license_supplier.' was NOT created');
}
}
// Add the license
$license = new License();
$license->name = e($user_license_name);
if ($user_license_purchase_date!='') {
$license->purchase_date = $user_license_purchase_date;
} else {
$license->purchase_date = null;
}
$license->serial = e($user_license_serial);
$license->seats = e($user_license_seats);
$license->supplier_id = $supplier->id;
$license->user_id = 1;
if ($user_license_purchase_date!='') {
$license->purchase_date = $user_license_purchase_date;
} else {
$license->purchase_date = null;
}
$license->license_name = $user_licensed_to_name;
$license->license_email = $user_licensed_to_email;
$license->notes = e($user_license_notes);
if ($license->save()) {
$this->comment('License '.$user_license_name.' with serial number '.$user_license_serial.' was created');
$license_seat_created = 0;
for ($x = 0; $x < $user_license_seats; $x++) {
// Create the license seat entries
$license_seat = new LicenseSeat();
$license_seat->license_id = $license->id;
// Only assign the first seat to the user
if ($x==0) {
$license_seat->assigned_to = $user->id;
} else {
$license_seat->assigned_to = null;
}
if ($license_seat->save()) {
$license_seat_created++;
}
}
if ($license_seat_created > 0) {
$this->comment($license_seat_created.' seats were created');
} else {
$this->comment('Something went wrong! NO seats for '.$user_license_name.' were created');
}
} else {
$this->comment('Something went wrong! License '.$user_license_name.' was NOT created');
}
$this->comment('=====================================');
return true;
});
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('filename', InputArgument::REQUIRED, 'File for the CSV import.'),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('domain', null, InputOption::VALUE_REQUIRED, 'Email domain for generated email addresses.', null),
array('email_format', null, InputOption::VALUE_REQUIRED, 'The format of the email addresses that should be generated. Options are firstname.lastname, firstname, filastname', null),
array('testrun', null, InputOption::VALUE_REQUIRED, 'Test the output without writing to the database or not.', null),
);
}
}
@@ -0,0 +1,981 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use League\Csv\Reader;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use App\Models\CustomField;
use DB;
use App\Models\Setting;
use Illuminate\Database\Eloquent\Model;
ini_set('max_execution_time', 600); //600 seconds = 10 minutes
ini_set('memory_limit', '500M');
/**
* Class ObjectImportCommand
*/
class ObjectImportCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:import';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import Items from CSV';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$filename = $this->argument('filename');
if (!$this->option('web-importer')) {
$logFile = $this->option('logfile');
\Log::useFiles($logFile);
if ($this->option('testrun')) {
$this->comment('====== TEST ONLY Asset Import for '.$filename.' ====');
$this->comment('============== NO DATA WILL BE WRITTEN ==============');
} else {
$this->comment('======= Importing Assets from '.$filename.' =========');
}
}
if (! ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
$csv = Reader::createFromPath($this->argument('filename'));
$csv->setNewline("\r\n");
$results = $csv->fetchAssoc();
$newarray = null;
foreach ($results as $index => $arraytoNormalize) {
$internalnewarray = array_change_key_case($arraytoNormalize);
$newarray[$index] = $internalnewarray;
}
$this->locations = Location::All(['name', 'id']);
$this->categories = Category::All(['name', 'category_type', 'id']);
$this->manufacturers = Manufacturer::All(['name', 'id']);
$this->asset_models = AssetModel::All(['name','modelno','category_id','manufacturer_id', 'id']);
$this->companies = Company::All(['name', 'id']);
$this->status_labels = Statuslabel::All(['name', 'id']);
$this->suppliers = Supplier::All(['name', 'id']);
$this->assets = Asset::all(['asset_tag']);
$this->accessories = Accessory::All(['name']);
$this->consumables = Consumable::All(['name']);
$this->customfields = CustomField::All(['name']);
$bar = null;
if (!$this->option('web-importer')) {
$bar = $this->output->createProgressBar(count($newarray));
}
// Loop through the records
DB::transaction(function () use (&$newarray, $bar) {
Model::unguard();
$item_type = strtolower($this->option('item-type'));
foreach ($newarray as $row) {
// Let's just map some of these entries to more user friendly words
// Fetch general items here, fetch item type specific items in respective methods
/** @var Asset, License, Accessory, or Consumable $item_type */
$item_category = $this->array_smart_fetch($row, "category");
$item_company_name = $this->array_smart_fetch($row, "company");
$item_location = $this->array_smart_fetch($row, "location");
$item_status_name = $this->array_smart_fetch($row, "status");
$item["item_name"] = $this->array_smart_fetch($row, "item name");
if ($this->array_smart_fetch($row, "purchase date")!='') {
$item["purchase_date"] = date("Y-m-d 00:00:01", strtotime($this->array_smart_fetch($row, "purchase date")));
} else {
$item["purchase_date"] = null;
}
$item["purchase_cost"] = $this->array_smart_fetch($row, "purchase cost");
$item["order_number"] = $this->array_smart_fetch($row, "order number");
$item["notes"] = $this->array_smart_fetch($row, "notes");
$item["quantity"] = $this->array_smart_fetch($row, "quantity");
$item["requestable"] = $this->array_smart_fetch($row, "requestable");
$item["asset_tag"] = $this->array_smart_fetch($row, "asset tag");
$this->current_assetId = $item["item_name"];
if ($item["asset_tag"] != '') {
$this->current_assetId = $item["asset_tag"];
}
$this->log('Category: ' . $item_category);
$this->log('Location: ' . $item_location);
$this->log('Purchase Date: ' . $item["purchase_date"]);
$this->log('Purchase Cost: ' . $item["purchase_cost"]);
$this->log('Company Name: ' . $item_company_name);
$this->log('Status: ' . $item_status_name);
$item["user"] = $this->createOrFetchUser($row);
$item["location"] = $this->createOrFetchLocation($item_location);
$item["category"] = $this->createOrFetchCategory($item_category, $item_type);
$item["manufacturer"] = $this->createOrFetchManufacturer($row);
$item["company"] = $this->createOrFetchCompany($item_company_name);
$item["status_label"] = $this->createOrFetchStatusLabel($item_status_name);
switch ($item_type) {
case "asset":
// -----------------------------
// CUSTOM FIELDS
// -----------------------------
// Loop through custom fields in the database and see if we have any matches in the CSV
foreach ($this->customfields as $customfield) {
if ($item['custom_fields'][$customfield->db_column_name()] = $this->array_smart_custom_field_fetch($row, $customfield)) {
$this->log('Custom Field '. $customfield->name.': '.$this->array_smart_custom_field_fetch($row, $customfield));
}
}
$this->createAssetIfNotExists($row, $item);
break;
case "accessory":
$this->createAccessoryIfNotExists($item);
break;
case 'consumable':
$this->createConsumableIfNotExists($item);
break;
}
if (!$this->option('web-importer')) {
$bar->advance();
}
$this->log('------------- Action Summary ----------------');
}
});
if (!$this->option('web-importer')) {
$bar->finish();
}
$this->log('=====================================');
if (!$this->option('web-importer')) {
if (!empty($this->errors)) {
$this->comment("The following Errors were encountered.");
foreach ($this->errors as $asset => $error) {
$this->comment('Error: Item: ' . $asset . 'failed validation: ' . json_encode($error));
}
} else {
$this->comment("All Items imported successfully!");
}
} else {
if (empty($this->errors)) {
return 0;
} else {
$this->comment(json_encode($this->errors)); //Send a big string to the
return 1;
}
}
$this->comment("");
return 2;
}
// Tracks the current item for error messages
private $current_assetId;
// An array of errors encountered while parsing
private $errors;
public function jsonError($field, $errorString)
{
$this->errors[$this->current_assetId][$field] = $errorString;
if ($this->option('verbose')) {
parent::error($field . $errorString);
}
}
/**
* Log a message to file, configurable by the --log-file parameter.
* If a warning message is passed, we'll spit it to the console as well.
*
* @author Daniel Melzter
* @since 3.0
* @param string $string
* @param string $level
*/
private function log($string, $level = 'info')
{
if ($this->option('web-importer')) {
return;
}
if ($level === 'warning') {
\Log::warning($string);
$this->comment($string);
} else {
\Log::Info($string);
if ($this->option('verbose')) {
$this->comment($string);
}
}
}
/**
* Check to see if the given key exists in the array, and trim excess white space before returning it
*
* @author Daniel Melzter
* @since 3.0
* @param $array array
* @param $key string
* @param $default string
* @return string
*/
public function array_smart_fetch(array $array, $key, $default = '')
{
return array_key_exists($key, $array) ? e(trim($array[ $key ])) : $default;
}
/**
* Figure out the fieldname of the custom field
*
* @author A. Gianotto <snipe@snipe.net>
* @since 3.0
* @param $array array
* @return string
*/
public function array_smart_custom_field_fetch(array $array, $key)
{
$index_name = strtolower($key->name);
return array_key_exists($index_name, $array) ? e(trim($array[$index_name])) : '';
}
private $asset_models;
/**
* Select the asset model if it exists, otherwise create it.
*
* @author Daniel Melzter
* @since 3.0
* @param array
* @param $category Category
* @param $manufacturer Manufacturer
* @return Model
* @internal param $asset_modelno string
*/
public function createOrFetchAssetModel(array $row, $category, $manufacturer)
{
$asset_model_name = $this->array_smart_fetch($row, "model name");
$asset_modelno = $this->array_smart_fetch($row, "model number");
if (empty($asset_model_name)) {
$asset_model_name='Unknown';
}
if (empty($asset_modelno)) {
$asset_modelno='';
}
$this->log('Model Name: ' . $asset_model_name);
$this->log('Model No: ' . $asset_modelno);
foreach ($this->asset_models as $tempmodel) {
if ((strcasecmp($tempmodel->name, $asset_model_name) == 0)
&& $tempmodel->modelno == $asset_modelno
&& $tempmodel->category_id == $category->id
&& $tempmodel->manufacturer_id == $manufacturer->id ) {
$this->log('A matching model ' . $asset_model_name . ' with model number ' . $asset_modelno . ' already exists');
return $tempmodel;
}
}
$asset_model = new AssetModel();
$asset_model->name = $asset_model_name;
$asset_model->manufacturer_id = $manufacturer->id;
$asset_model->modelno = $asset_modelno;
$asset_model->category_id = $category->id;
$asset_model->user_id = $this->option('user_id');
if (!$this->option('testrun')) {
if ($asset_model->save()) {
$this->asset_models->add($asset_model);
$this->log('Asset Model ' . $asset_model_name . ' with model number ' . $asset_modelno . ' was created');
return $asset_model;
} else {
$this->jsonError('Asset Model "' . $asset_model_name . '"', $asset_model->getErrors());
return $asset_model;
}
} else {
$this->asset_models->add($asset_model);
return $asset_model;
}
}
private $categories;
/**
* Finds a category with the same name and item type in the database, otherwise creates it
*
* @author Daniel Melzter
* @since 3.0
* @param $asset_category string
* @param $item_type string
* @return Category
*/
public function createOrFetchCategory($asset_category, $item_type)
{
if (empty($asset_category)) {
$asset_category = 'Unnamed Category';
}
foreach ($this->categories as $tempcategory) {
if ((strcasecmp($tempcategory->name, $asset_category) == 0) && $tempcategory->category_type === $item_type) {
$this->log('Category ' . $asset_category . ' already exists');
return $tempcategory;
}
}
$category = new Category();
$category->name = $asset_category;
$category->category_type = $item_type;
$category->user_id = $this->option('user_id');
if (!$this->option('testrun')) {
if ($category->save()) {
$this->categories->add($category);
$this->log('Category ' . $asset_category . ' was created');
return $category;
} else {
$this->jsonError('Category "'. $asset_category. '"', $category->getErrors());
return $category;
}
} else {
$this->categories->add($category);
return $category;
}
}
private $companies;
/**
* Fetch an existing company, or create new if it doesn't exist
*
* @author Daniel Melzter
* @since 3.0
* @param $asset_company_name string
* @return Company
*/
public function createOrFetchCompany($asset_company_name)
{
foreach ($this->companies as $tempcompany) {
if (strcasecmp($tempcompany->name, $asset_company_name) == 0) {
$this->log('A matching Company ' . $asset_company_name . ' already exists');
return $tempcompany;
}
}
$company = new Company();
$company->name = $asset_company_name;
if (!$this->option('testrun')) {
if ($company->save()) {
$this->companies->add($company);
$this->log('Company ' . $asset_company_name . ' was created');
return $company;
} else {
$this->log('Company', $company->getErrors());
}
} else {
$this->companies->add($company);
return $company;
}
}
private $status_labels;
/**
* Fetch the existing status label or create new if it doesn't exist.
*
* @author Daniel Melzter
* @since 3.0
* @param string $asset_statuslabel_name
* @return Company
*/
public function createOrFetchStatusLabel($asset_statuslabel_name)
{
if (empty($asset_statuslabel_name)) {
return;
}
foreach ($this->status_labels as $tempstatus) {
if (strcasecmp($tempstatus->name, $asset_statuslabel_name) == 0) {
$this->log('A matching Status ' . $asset_statuslabel_name . ' already exists');
return $tempstatus;
}
}
$status = new Statuslabel();
$status->name = $asset_statuslabel_name;
if (!$this->option('testrun')) {
if ($status->save()) {
$this->status_labels->add($status);
$this->log('Status ' . $asset_statuslabel_name . ' was created');
return $status;
} else {
$this->jsonError('Status "'. $asset_statuslabel_name . '"', $status->getErrors());
return $status;
}
} else {
$this->status_labels->add($status);
return $status;
}
}
private $manufacturers;
/**
* Finds a manufacturer with matching name, otherwise create it.
*
* @author Daniel Melzter
* @since 3.0
* @param $row array
* @return Manufacturer
* @internal param $asset_mfgr string
*/
public function createOrFetchManufacturer(array $row)
{
$asset_mfgr = $this->array_smart_fetch($row, "manufacturer");
if (empty($asset_mfgr)) {
$asset_mfgr='Unknown';
}
$this->log('Manufacturer ID: ' . $asset_mfgr);
foreach ($this->manufacturers as $tempmanufacturer) {
if (strcasecmp($tempmanufacturer->name, $asset_mfgr) == 0) {
$this->log('Manufacturer ' . $asset_mfgr . ' already exists') ;
return $tempmanufacturer;
}
}
//Otherwise create a manufacturer.
$manufacturer = new Manufacturer();
$manufacturer->name = $asset_mfgr;
$manufacturer->user_id = $this->option('user_id');
if (!$this->option('testrun')) {
if ($manufacturer->save()) {
$this->manufacturers->add($manufacturer);
$this->log('Manufacturer ' . $manufacturer->name . ' was created');
return $manufacturer;
} else {
$this->jsonError('Manufacturer "'. $manufacturer->name . '"', $manufacturer->getErrors());
return $manufacturer;
}
} else {
$this->manufacturers->add($manufacturer);
return $manufacturer;
}
}
/**
* @var
*/
private $locations;
/**
* Checks the DB to see if a location with the same name exists, otherwise create it
*
* @author Daniel Melzter
* @since 3.0
* @param $asset_location string
* @return Location
*/
public function createOrFetchLocation($asset_location)
{
foreach ($this->locations as $templocation) {
if (strcasecmp($templocation->name, $asset_location) == 0) {
$this->log('Location ' . $asset_location . ' already exists');
return $templocation;
}
}
// No matching locations in the collection, create a new one.
$location = new Location();
if (!empty($asset_location)) {
$location->name = $asset_location;
$location->address = '';
$location->city = '';
$location->state = '';
$location->country = '';
$location->user_id = $this->option('user_id');
if (!$this->option('testrun')) {
if ($location->save()) {
$this->locations->add($location);
$this->log('Location ' . $asset_location . ' was created');
return $location;
} else {
$this->log('Location', $location->getErrors()) ;
return $location;
}
} else {
$this->locations->add($location);
return $location;
}
} else {
$this->log('No location given, so none created.');
return $location;
}
}
private $suppliers;
/**
* Fetch an existing supplier or create new if it doesn't exist
*
* @author Daniel Melzter
* @since 3.0
* @param $row array
* @return Supplier
*/
public function createOrFetchSupplier(array $row)
{
$supplier_name = $this->array_smart_fetch($row, "supplier");
if (empty($supplier_name)) {
$supplier_name='Unknown';
}
foreach ($this->suppliers as $tempsupplier) {
if (strcasecmp($tempsupplier->name, $supplier_name) == 0) {
$this->log('A matching Company ' . $supplier_name . ' already exists');
return $tempsupplier;
}
}
$supplier = new Supplier();
$supplier->name = $supplier_name;
$supplier->user_id = $this->option('user_id');
if (!$this->option('testrun')) {
if ($supplier->save()) {
$this->suppliers->add($supplier);
$this->log('Supplier ' . $supplier_name . ' was created');
return $supplier;
} else {
$this->log('Supplier', $supplier->getErrors());
return $supplier;
}
} else {
$this->suppliers->add($supplier);
return $supplier;
}
}
/**
* Finds the user matching given data, or creates a new one if there is no match
*
* @author Daniel Melzter
* @since 3.0
* @param $row array
* @return User Model w/ matching name
* @internal param string $user_username Username extracted from CSV
* @internal param string $user_email Email extracted from CSV
* @internal param string $first_name
* @internal param string $last_name
*/
public function createOrFetchUser($row)
{
$user_name = $this->array_smart_fetch($row, "name");
$user_email = $this->array_smart_fetch($row, "email");
$user_username = $this->array_smart_fetch($row, "username");
// A number was given instead of a name
if (is_numeric($user_name)) {
$this->log('User '.$user_name.' is not a name - assume this user already exists');
$user_username = '';
$first_name = '';
$last_name = '';
// No name was given
} elseif (empty($user_name)) {
$this->log('No user data provided - skipping user creation, just adding asset');
$first_name = '';
$last_name = '';
//$user_username = '';
} else {
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
$first_name = $user_email_array['first_name'];
$last_name = $user_email_array['last_name'];
if ($user_email=='') {
$user_email = $user_email_array['username'].'@'.Setting::getSettings()->email_domain;
}
if ($user_username=='') {
if ($this->option('username_format')=='email') {
$user_username = $user_email;
} else {
$user_name_array = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $user_name);
$user_username = $user_name_array['username'];
}
}
}
$this->log("--- User Data ---");
$this->log('Full Name: ' . $user_name);
$this->log('First Name: ' . $first_name);
$this->log('Last Name: ' . $last_name);
$this->log('Username: ' . $user_username);
$this->log('Email: ' . $user_email);
$this->log('--- End User Data ---');
if ($this->option('testrun')) {
return new User;
}
if (!empty($user_username)) {
if ($user = User::MatchEmailOrUsername($user_username, $user_email)
->whereNotNull('username')->first()) {
$this->log('User '.$user_username.' already exists');
} elseif (( $first_name != '') && ($last_name != '') && ($user_username != '')) {
$user = new \App\Models\User;
$password = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $user_username;
$user->email = $user_email;
$user->password = bcrypt($password);
$user->activated = 1;
if ($user->save()) {
$this->log('User '.$first_name.' created');
} else {
$this->jsonError('User "' . $first_name . '"', $user->getErrors());
}
} else {
$user = new User;
}
} else {
$user = new User;
}
return $user;
}
private $assets;
/**
* Create the asset if it doesn't exist.
*
* @author Daniel Melzter
* @since 3.0
* @param array $row
* @param array $item
*/
public function createAssetIfNotExists(array $row, array $item)
{
$asset_serial = $this->array_smart_fetch($row, "serial number");
$asset_image = $this->array_smart_fetch($row, "image");
$asset_warranty_months = intval($this->array_smart_fetch($row, "warranty months"));
if (empty($asset_warranty_months)) {
$asset_warranty_months = null;
}
// Check for the asset model match and create it if it doesn't exist
$asset_model = $this->createOrFetchAssetModel($row, $item["category"], $item["manufacturer"]);
$supplier = $this->createOrFetchSupplier($row);
$this->log('Serial No: '.$asset_serial);
$this->log('Asset Tag: '.$item['asset_tag']);
$this->log('Notes: '.$item["notes"]);
$this->log('Warranty Months: ' . $asset_warranty_months);
foreach ($this->assets as $tempasset) {
if (strcasecmp($tempasset->asset_tag, $item['asset_tag']) == 0) {
$this->log('A matching Asset ' . $item['asset_tag'] . ' already exists');
return;
}
}
if ($item["status_label"]) {
$status_id = $item["status_label"]->id;
} else {
// FIXME: We're already grabbing the list of statuses, we should probably not hardcode here
$this->log("No status field found, defaulting to id 1.");
$status_id = 1;
}
$asset = new Asset();
$asset->name = $item["item_name"];
if ($item["purchase_date"] != '') {
$asset->purchase_date = $item["purchase_date"];
} else {
$asset->purchase_date = null;
}
if (array_key_exists('custom_fields', $item)) {
foreach ($item['custom_fields'] as $custom_field => $val) {
$asset->{$custom_field} = $val;
}
}
if (!empty($item["purchase_cost"])) {
//TODO How to generalize this for not USD?
$purchase_cost = substr($item["purchase_cost"], 0, 1) === '$' ? substr($item["purchase_cost"], 1) : $item["purchase_cost"];
$asset->purchase_cost = number_format($purchase_cost, 2);
$this->log("Asset cost parsed: " . $asset->purchase_cost);
} else {
$asset->purchase_cost = 0.00;
}
$asset->serial = $asset_serial;
$asset->asset_tag = $item['asset_tag'];
$asset->warranty_months = $asset_warranty_months;
if ($asset_model) {
$asset->model_id = $asset_model->id;
}
if ($item["user"]) {
$asset->assigned_to = $item["user"]->id;
}
if ($item["location"]) {
$asset->rtd_location_id = $item["location"]->id;
}
$asset->user_id = $this->option('user_id');
$this->log("status_id: " . $status_id);
$asset->status_id = $status_id;
if ($item["company"]) {
$asset->company_id = $item["company"]->id;
}
$asset->order_number = $item["order_number"];
if ($supplier) {
$asset->supplier_id = $supplier->id;
}
$asset->notes = $item["notes"];
$asset->image = $asset_image;
$this->assets->add($asset);
if (!$this->option('testrun')) {
if ($asset->save()) {
$this->log('Asset ' . $item["item_name"] . ' with serial number ' . $asset_serial . ' was created');
} else {
$this->jsonError('Asset', $asset->getErrors());
}
} else {
return;
}
}
private $accessories;
/**
* Create an accessory if a duplicate does not exist
*
* @author Daniel Melzter
* @since 3.0
* @param $item array
*/
public function createAccessoryIfNotExists(array $item)
{
$this->log("Creating Accessory");
foreach ($this->accessories as $tempaccessory) {
if (strcasecmp($tempaccessory->name, $item["item_name"]) == 0) {
$this->log('A matching Accessory ' . $item["item_name"] . ' already exists. ');
// FUTURE: Adjust quantity on import maybe?
return;
}
}
$accessory = new Accessory();
$accessory->name = $item["item_name"];
if (!empty($item["purchase_date"])) {
$accessory->purchase_date = $item["purchase_date"];
} else {
$accessory->purchase_date = null;
}
if (!empty($item["purchase_cost"])) {
$accessory->purchase_cost = number_format(e($item["purchase_cost"]), 2);
} else {
$accessory->purchase_cost = 0.00;
}
if ($item["location"]) {
$accessory->location_id = $item["location"]->id;
}
$accessory->user_id = $this->option('user_id');
if ($item["company"]) {
$accessory->company_id = $item["company"]->id;
}
$accessory->order_number = $item["order_number"];
if ($item["category"]) {
$accessory->category_id = $item["category"]->id;
}
//TODO: Implement
// $accessory->notes = e($item_notes);
$accessory->requestable = filter_var($item["requestable"], FILTER_VALIDATE_BOOLEAN);
//Must have at least zero of the item if we import it.
if ($item["quantity"] > -1) {
$accessory->qty = $item["quantity"];
} else {
$accessory->qty = 1;
}
if (!$this->option('testrun')) {
if ($accessory->save()) {
$this->log('Accessory ' . $item["item_name"] . ' was created');
// $this->comment('Accessory ' . $item["item_name"] . ' was created');
} else {
$this->jsonError('Accessory', $accessory->getErrors()) ;
}
} else {
$this->log('TEST RUN - Accessory ' . $item["item_name"] . ' not created');
}
}
private $consumables;
/**
* Create a consumable if a duplicate does not exist
*
* @author Daniel Melzter
* @since 3.0
* @param $item array
*/
public function createConsumableIfNotExists(array $item)
{
$this->log("Creating Consumable");
foreach ($this->consumables as $tempconsumable) {
if (strcasecmp($tempconsumable->name, $item["item_name"]) == 0) {
$this->log("A matching consumable " . $item["item_name"] . " already exists");
//TODO: Adjust quantity if different maybe?
return;
}
}
$consumable = new Consumable();
$consumable->name = $item["item_name"];
if (!empty($item["purchase_date"])) {
$consumable->purchase_date = $item["purchase_date"];
} else {
$consumable->purchase_date = null;
}
if (!empty($item["purchase_cost"])) {
$consumable->purchase_cost = number_format(e($item["purchase_cost"]), 2);
} else {
$consumable->purchase_cost = 0.00;
}
$consumable->location_id = $item["location"]->id;
$consumable->user_id = $this->option('user_id');
$consumable->company_id = $item["company"]->id;
$consumable->order_number = $item["order_number"];
$consumable->category_id = $item["category"]->id;
// TODO:Implement
//$consumable->notes= e($item_notes);
$consumable->requestable = filter_var($item["requestable"], FILTER_VALIDATE_BOOLEAN);
if ($item["quantity"] > -1) {
$consumable->qty = $item["quantity"];
} else {
$consumable->qty = 1;
}
if (!$this->option("testrun")) {
if ($consumable->save()) {
$this->log("Consumable " . $item["item_name"] . ' was created');
// $this->comment("Consumable " . $item["item_name"] . ' was created');
} else {
$this->jsonError('Consumable', $consumable->getErrors());
}
} else {
$this->log('TEST RUN - Consumable ' . $item['item_name'] . ' not created');
}
}
/**
* Get the console command arguments.
*
* @author Daniel Melzter
* @since 3.0
* @return array
*/
protected function getArguments()
{
return array(
array('filename', InputArgument::REQUIRED, 'File for the CSV import.'),
);
}
/**
* Get the console command options.
*
* @author Daniel Melzter
* @since 3.0
* @return array
*/
protected function getOptions()
{
return array(
array('email_format', null, InputOption::VALUE_REQUIRED, 'The format of the email addresses that should be generated. Options are firstname.lastname, firstname, filastname', null),
array('username_format', null, InputOption::VALUE_REQUIRED, 'The format of the username that should be generated. Options are firstname.lastname, firstname, filastname, email', null),
array('testrun', null, InputOption::VALUE_NONE, 'If set, will parse and output data without adding to database', null),
array('logfile', null, InputOption::VALUE_REQUIRED, 'The path to log output to. storage/logs/importer.log by default', storage_path('logs/importer.log') ),
array('item-type', null, InputOption::VALUE_REQUIRED, 'Item Type To import. Valid Options are Asset, Consumable, Or Accessory', 'Asset'),
array('web-importer', null, InputOption::VALUE_NONE, 'Internal: packages output for use with the web importer'),
array('user_id', null, InputOption::VALUE_REQUIRED, 'ID of user creating items', 1)
);
}
}
+128
View File
@@ -0,0 +1,128 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use DB;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\Depreciation;
use App\Models\Group;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Statuslabel;
use App\Models\Supplier;
class PaveIt extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:pave
{--soft : Perform a "Soft" Delete, leaving all migrations, table structure, and the first user in place.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Pave the database to start over. This should ALMOST NEVER BE USED. (It is primarily a quick tool for developers.)';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->confirm("\n****************************************************\nTHIS WILL DELETE ALL OF THE DATA IN YOUR DATABASE. \nThere is NO undo. This WILL destroy ALL of your data. \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) {
if ($this->option('soft')) {
Accessory::getQuery()->delete();
Asset::getQuery()->delete();
Category::getQuery()->delete();
Company::getQuery()->delete();
Component::getQuery()->delete();
Consumable::getQuery()->delete();
Depreciation::getQuery()->delete();
License::getQuery()->delete();
LicenseSeat::getQuery()->delete();
Location::getQuery()->delete();
Manufacturer::getQuery()->delete();
AssetModel::getQuery()->delete();
Statuslabel::getQuery()->delete();
Supplier::getQuery()->delete();
Group::getQuery()->delete();
DB::statement('delete from accessories_users');
DB::statement('delete from asset_logs');
DB::statement('delete from asset_maintenances');
DB::statement('delete from asset_uploads');
DB::statement('delete from consumables_users');
DB::statement('delete from custom_field_custom_fieldset');
DB::statement('delete from custom_fields');
DB::statement('delete from custom_fieldsets');
DB::statement('delete from components_assets');
DB::statement('delete from password_resets');
DB::statement('delete from requested_assets');
DB::statement('delete from requests');
DB::statement('delete from throttle');
DB::statement('delete from users_groups');
DB::statement('delete from users WHERE id!=1');
} else {
\DB::statement('drop table IF EXISTS accessories_users');
\DB::statement('drop table IF EXISTS accessories');
\DB::statement('drop table IF EXISTS asset_logs');
\DB::statement('drop table IF EXISTS asset_maintenances');
\DB::statement('drop table IF EXISTS asset_uploads');
\DB::statement('drop table IF EXISTS assets');
\DB::statement('drop table IF EXISTS categories');
\DB::statement('drop table IF EXISTS companies');
\DB::statement('drop table IF EXISTS consumables_users');
\DB::statement('drop table IF EXISTS consumables');
\DB::statement('drop table IF EXISTS custom_field_custom_fieldset');
\DB::statement('drop table IF EXISTS custom_fields');
\DB::statement('drop table IF EXISTS custom_fieldsets');
\DB::statement('drop table IF EXISTS depreciations');
\DB::statement('drop table IF EXISTS groups');
\DB::statement('drop table IF EXISTS history');
\DB::statement('drop table IF EXISTS components');
\DB::statement('drop table IF EXISTS components_assets');
\DB::statement('drop table IF EXISTS license_seats');
\DB::statement('drop table IF EXISTS licenses');
\DB::statement('drop table IF EXISTS locations');
\DB::statement('drop table IF EXISTS manufacturers');
\DB::statement('drop table IF EXISTS models');
\DB::statement('drop table IF EXISTS migrations');
\DB::statement('drop table IF EXISTS password_resets');
\DB::statement('drop table IF EXISTS requested_assets');
\DB::statement('drop table IF EXISTS requests');
\DB::statement('drop table IF EXISTS settings');
\DB::statement('drop table IF EXISTS status_labels');
\DB::statement('drop table IF EXISTS suppliers');
\DB::statement('drop table IF EXISTS throttle');
\DB::statement('drop table IF EXISTS users_groups');
\DB::statement('drop table IF EXISTS users');
}
}
}
}
+174
View File
@@ -0,0 +1,174 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use DB;
use \App\Models\Asset;
use \App\Models\AssetModel;
use \App\Models\Location;
use \App\Models\Company;
use \App\Models\License;
use \App\Models\Accessory;
use \App\Models\Component;
use \App\Models\Consumable;
use \App\Models\Category;
use \App\Models\User;
use \App\Models\Supplier;
use \App\Models\Manufacturer;
use \App\Models\Depreciation;
use \App\Models\Statuslabel;
class Purge extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:purge {--force=false}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Purge all soft-deleted deleted records in the database. This will rewrite history for items that have been edited, or checked in or out. It will also reqrite history for users associated with deleted items.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$force = $this->option('force');
if (($this->confirm("\n****************************************************\nTHIS WILL PURGE ALL SOFT-DELETED ITEMS IN YOUR SYSTEM. \nThere is NO undo. This WILL permanently destroy \nALL of your deleted data. \n****************************************************\n\nDo you wish to continue? No backsies! [y|N]")) || $force == 'true') {
/**
* Delete assets
*/
$assets = Asset::whereNotNull('deleted_at')->withTrashed()->get();
$assetcount = $assets->count();
$this->info($assets->count().' assets purged.');
$asset_assoc = 0;
foreach ($assets as $asset) {
$this->info('- Asset "'.$asset->showAssetName().'" deleted.');
$asset_assoc += $asset->assetlog()->count();
$asset->assetlog()->forceDelete();
$asset->forceDelete();
}
$this->info($asset_assoc.' corresponding log records purged.');
$locations = Location::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($locations->count().' locations purged.');
foreach ($locations as $location) {
$this->info('- Location "'.$location->name.'" deleted.');
$location->forceDelete();
}
$accessories = Accessory::whereNotNull('deleted_at')->withTrashed()->get();
$accessory_assoc=0;
$this->info($accessories->count().' accessories purged.');
foreach ($accessories as $accessory) {
$this->info('- Accessory "'.$accessory->name.'" deleted.');
$accessory_assoc += $accessory->assetlog()->count();
$accessory->assetlog()->forceDelete();
$accessory->forceDelete();
}
$this->info($accessory_assoc.' corresponding log records purged.');
$consumables = Consumable::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($consumables->count().' consumables purged.');
foreach ($consumables as $consumable) {
$this->info('- Consumable "'.$consumable->name.'" deleted.');
$consumable->assetlog()->forceDelete();
$consumable->forceDelete();
}
$components = Component::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($components->count().' components purged.');
foreach ($components as $component) {
$this->info('- Component "'.$component->name.'" deleted.');
$component->assetlog()->forceDelete();
$component->forceDelete();
}
$licenses = License::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($licenses->count().' licenses purged.');
foreach ($licenses as $license) {
$this->info('- License "'.$license->name.'" deleted.');
$license->assetlog()->forceDelete();
$license->licenseseats()->forceDelete();
$license->forceDelete();
}
$models = AssetModel::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($models->count().' asset models purged.');
foreach ($models as $model) {
$this->info('- Asset Model "'.$model->name.'" deleted.');
$model->forceDelete();
}
$categories = Category::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($categories->count().' categories purged.');
foreach ($categories as $category) {
$this->info('- Category "'.$category->name.'" deleted.');
$category->forceDelete();
}
$suppliers = Supplier::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($suppliers->count().' suppliers purged.');
foreach ($suppliers as $supplier) {
$this->info('- Supplier "'.$supplier->name.'" deleted.');
$supplier->forceDelete();
}
$users = User::whereNotNull('deleted_at')->where('show_in_list', '!=', '0')->withTrashed()->get();
$this->info($users->count().' users purged.');
$user_assoc = 0;
foreach ($users as $user) {
$this->info('- User "'.$user->username.'" deleted.');
$user_assoc += $user->userlog()->count();
$user->userlog()->forceDelete();
$user->forceDelete();
}
$this->info($user_assoc.' corresponding user log records purged.');
$manufacturers = Manufacturer::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($manufacturers->count().' manufacturers purged.');
foreach ($manufacturers as $manufacturer) {
$this->info('- Manufacturer "'.$manufacturer->name.'" deleted.');
$manufacturer->forceDelete();
}
$status_labels = Statuslabel::whereNotNull('deleted_at')->withTrashed()->get();
$this->info($status_labels->count().' status labels purged.');
foreach ($status_labels as $status_label) {
$this->info('- Status Label "'.$status_label->name.'" deleted.');
$status_label->forceDelete();
}
} else {
$this->info('Action canceled. Nothing was purged.');
}
}
}
@@ -0,0 +1,133 @@
<?php
namespace App\Console\Commands;
use App\Models\Asset;
use App\Models\License;
use App\Models\Setting;
use DB;
use Illuminate\Console\Command;
class SendExpirationAlerts extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:expiring-alerts';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Check for expiring warrantees and service agreements, and sends out an alert email.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
// Expiring Assets
$expiring_assets = Asset::getExpiringWarrantee(Setting::getSettings()->alert_interval);
$this->info(count($expiring_assets).' expiring assets');
$asset_data['count'] = count($expiring_assets);
$asset_data['email_content'] ='';
$now = date("Y-m-d");
foreach ($expiring_assets as $asset) {
$expires = $asset->warrantee_expires();
$difference = round(abs(strtotime($expires) - strtotime($now))/86400);
if ($difference > 30) {
$asset_data['email_content'] .= '<tr style="background-color: #fcffa3;">';
} else {
$asset_data['email_content'] .= '<tr style="background-color:#d9534f;">';
}
$asset_data['email_content'] .= '<td><a href="'.config('app.url').'/hardware/'.e($asset->id).'/view">';
$asset_data['email_content'] .= $asset->showAssetName().'</a></td><td>'.e($asset->asset_tag).'</td>';
$asset_data['email_content'] .= '<td>'.e($asset->warrantee_expires()).'</td>';
$asset_data['email_content'] .= '<td>'.$difference.' days</td>';
$asset_data['email_content'] .= '<td>'.($asset->supplier ? e($asset->supplier->name) : '').'</td>';
$asset_data['email_content'] .= '<td>'.($asset->assigneduser ? e($asset->assigneduser->fullName()) : '').'</td>';
$asset_data['email_content'] .= '</tr>';
}
// Expiring licenses
$expiring_licenses = License::getExpiringLicenses(Setting::getSettings()->alert_interval);
$this->info(count($expiring_licenses).' expiring licenses');
$license_data['count'] = count($expiring_licenses);
$license_data['email_content'] = '';
foreach ($expiring_licenses as $license) {
$expires = $license->expiration_date;
$difference = round(abs(strtotime($expires) - strtotime($now))/86400);
if ($difference > 30) {
$license_data['email_content'] .= '<tr style="background-color: #fcffa3;">';
} else {
$license_data['email_content'] .= '<tr style="background-color:#d9534f;">';
}
$license_data['email_content'] .= '<td><a href="'.config('app.url').'/admin/licenses/'.$license->id.'/view">';
$license_data['email_content'] .= $license->name.'</a></td>';
$license_data['email_content'] .= '<td>'.$license->expiration_date.'</td>';
$license_data['email_content'] .= '<td>'.$difference.' days</td>';
$license_data['email_content'] .= '</tr>';
}
if ((Setting::getSettings()->alert_email!='') && (Setting::getSettings()->alerts_enabled==1)) {
if (count($expiring_assets) > 0) {
\Mail::send('emails.expiring-assets-report', $asset_data, function ($m) {
$m->to(explode(',', Setting::getSettings()->alert_email), Setting::getSettings()->site_name);
$m->subject('Expiring Assets Report');
});
}
if (count($expiring_licenses) > 0) {
\Mail::send('emails.expiring-licenses-report', $license_data, function ($m) {
$m->to(explode(',', Setting::getSettings()->alert_email), Setting::getSettings()->site_name);
$m->subject('Expiring Licenses Report');
});
}
} else {
if (Setting::getSettings()->alert_email=='') {
echo "Could not send email. No alert email configured in settings. \n";
} elseif (Setting::getSettings()->alerts_enabled!=1) {
echo "Alerts are disabled in the settings. No mail will be sent. \n";
}
}
}
}
@@ -0,0 +1,68 @@
<?php
namespace App\Console\Commands;
use App\Models\Setting;
use DB;
use Mail;
use App\Helpers\Helper;
use Illuminate\Console\Command;
class SendInventoryAlerts extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:inventory-alerts';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command checks for low inventory, and sends out an alert email.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ((Setting::getSettings()->alert_email!='') && (Setting::getSettings()->alerts_enabled==1)) {
$data['data'] = Helper::checkLowInventory();
$data['count'] = count($data['data']);
if (count($data['data']) > 0) {
\Mail::send('emails.low-inventory', $data, function ($m) {
$m->to(explode(',', Setting::getSettings()->alert_email), Setting::getSettings()->site_name);
$m->subject('Low Inventory Report');
});
}
} else {
if (Setting::getSettings()->alert_email=='') {
echo "Could not send email. No alert email configured in settings. \n";
} elseif (Setting::getSettings()->alerts_enabled!=1) {
echo "Alerts are disabled in the settings. No mail will be sent. \n";
}
}
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class SystemBackup extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'snipeit:backup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command creates a database dump and zips up all of the uploaded files in the upload directories.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
//
$this->call('backup:run');
}
}
+92
View File
@@ -0,0 +1,92 @@
<?php
namespace App\Console\Commands;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Console\Command;
class Versioning extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'versioning:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate and update app\'s version via git.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
// Path to the file containing your version
// This will be overwritten everything you commit a message
$versionFile = app_path().'/config/version.php';
// The git's output
// get the argument passed in the git command
$hash_version = $this->argument('app_version');
// discard the commit hash
$version = explode('-', $hash_version);
$realVersion = $version[0] . '-' . $version[1];
// save the version array to a variable
$array = var_export(array('app_version' => $realVersion,'hash_version' => $hash_version), true);
// Construct our file content
$content = <<<CON
<?php
return $array;
CON;
// And finally write the file and output the current version
\File::put($versionFile, $content);
$this->line('Setting version: '. \config('version.latest'));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('app_version', InputArgument::REQUIRED, 'version number is required.'),
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
);
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\PaveIt::class,
Commands\CreateAdmin::class,
Commands\SendExpirationAlerts::class,
Commands\SendInventoryAlerts::class,
Commands\LicenseImportCommand::class,
Commands\ObjectImportCommand::class,
Commands\Versioning::class,
Commands\SystemBackup::class,
Commands\DisableLDAP::class,
Commands\Purge::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('snipeit:inventory-alerts')->daily();
$schedule->command('snipeit:expiring-alerts')->daily();
$schedule->command('snipeit:backup')->weekly();
$schedule->command('backup:clean')->daily();
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Events;
abstract class Event
{
//
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return redirect()->back()->with('error', trans('general.token_expired'));
}
if ($this->isHttpException($e)) {
$statusCode = $e->getStatusCode();
switch ($statusCode) {
case '404':
return response()->view('layouts/basic', [
'content' => view('errors/404')
]);
}
}
return parent::render($request, $e);
}
}
+406
View File
@@ -0,0 +1,406 @@
<?php
namespace App\Helpers;
use DB;
use App\Models\Statuslabel;
use App\Models\Location;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\User;
use App\Models\Manufacturer;
use App\Models\Supplier;
use App\Models\Category;
use App\Models\Depreciation;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use App\Models\Component;
use App\Models\Accessory;
use App\Models\Consumable;
use App\Models\Asset;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class Helper
{
public static function parseEscapedMarkedown($str) {
$Parsedown = new \Parsedown();
if ($str) {
return $Parsedown->text(e($str));
}
}
// This doesn't do anything yet
public static function parseEmailList($emails)
{
$emails_array = explode(',', $emails);
return array_walk($emails_array, 'trim_value');
}
// This doesn't do anything yet
public static function trim_value(&$value)
{
return trim($value);
}
// Static colors for pie charts
public static function chartColors()
{
$colors = [
'#f56954',
'#00a65a',
'#f39c12',
'#00c0ef',
'#3c8dbc',
'#d2d6de',
'#3c8dbc',
'#3c8dbc',
'#3c8dbc',
];
return $colors;
}
// Static background (highlight) colors for pie charts
// This is not currently used, but might be in the near future.
public static function chartBackgroundColors()
{
$colors = [
'#f56954',
'#00a65a',
'#f39c12',
'#00c0ef',
'#3c8dbc',
'#d2d6de',
'#3c8dbc',
'#3c8dbc',
'#3c8dbc',
];
return $colors;
}
public static function ParseFloat($floatString)
{
// use comma for thousands until local info is property used
$LocaleInfo = localeconv();
$floatString = str_replace(",", "", $floatString);
$floatString = str_replace($LocaleInfo["decimal_point"], ".", $floatString);
return floatval($floatString);
}
public static function modelList()
{
$models = AssetModel::with('manufacturer')->get();
$model_array[''] = trans('general.select_model');
foreach ($models as $model) {
$model_array[$model->id] = $model->displayModelName();
}
return $model_array;
}
public static function companyList()
{
$company_list = array('0' => trans('general.select_company')) + DB::table('companies')
->orderBy('name', 'asc')
->pluck('name', 'id');
return $company_list;
}
public static function categoryList($category_type = null)
{
$categories = Category::orderBy('name', 'asc')
->whereNull('deleted_at')
->orderBy('name', 'asc');
if(!empty($category_type))
$categories = $categories->where('category_type', '=', $category_type);
$category_list = array('' => trans('general.select_category')) + $categories->pluck('name', 'id')->toArray();
return $category_list;
}
public static function suppliersList()
{
$supplier_list = array('' => trans('general.select_supplier')) + Supplier::orderBy('name', 'asc')
->orderBy('name', 'asc')
->pluck('name', 'id')->toArray();
return $supplier_list;
}
public static function statusLabelList()
{
$statuslabel_list = array('' => trans('general.select_statuslabel')) + Statuslabel::orderBy('name', 'asc')
->pluck('name', 'id')->toArray();
return $statuslabel_list;
}
public static function locationsList()
{
$location_list = array('' => trans('general.select_location')) + Location::orderBy('name', 'asc')
->pluck('name', 'id')->toArray();
return $location_list;
}
public static function manufacturerList()
{
$manufacturer_list = array('' => trans('general.select_manufacturer')) +
Manufacturer::orderBy('name', 'asc')
->pluck('name', 'id')->toArray();
return $manufacturer_list;
}
public static function statusTypeList()
{
$statuslabel_types = array('' => trans('admin/hardware/form.select_statustype')) + array('undeployable' => trans('admin/hardware/general.undeployable')) + array('pending' => trans('admin/hardware/general.pending')) + array('archived' => trans('admin/hardware/general.archived')) + array('deployable' => trans('admin/hardware/general.deployable'));
return $statuslabel_types;
}
public static function managerList()
{
$manager_list = array('' => trans('general.select_user')) +
User::where('deleted_at', '=', null)
->orderBy('last_name', 'asc')
->orderBy('first_name', 'asc')->get()
->lists('complete_name', 'id')->toArray();
return $manager_list;
}
public static function depreciationList()
{
$depreciation_list = ['' => 'Do Not Depreciate'] + Depreciation::orderBy('name', 'asc')
->pluck('name', 'id')->toArray();
return $depreciation_list;
}
public static function categoryTypeList()
{
$category_types = array('' => '','accessory' => 'Accessory', 'asset' => 'Asset', 'consumable' => 'Consumable','component' => 'Component');
return $category_types;
}
public static function usersList()
{
$users_list = array( '' => trans('general.select_user')) +
User::where('deleted_at', '=', null)
->where('show_in_list','=',1)
->orderBy('last_name', 'asc')
->orderBy('first_name', 'asc')->get()
->lists('complete_name', 'id')->toArray();
return $users_list;
}
public static function assetsList()
{
$assets_list = array('' => trans('general.select_asset')) + Asset::orderBy('name', 'asc')
->whereNull('deleted_at')
->pluck('name', 'id')->toArray();
return $assets_list;
}
public static function detailedAssetList()
{
$assets = array('' => trans('general.select_asset')) + Company::scopeCompanyables(Asset::all(), 'assets.company_id')->lists('detailed_name', 'id')->toArray();
return $assets;
}
public static function customFieldsetList()
{
$customfields = array('' => trans('admin/models/general.no_custom_field')) + CustomFieldset::pluck('name', 'id')->toArray();
return $customfields;
}
public static function predefined_formats()
{
$keys=array_keys(CustomField::$PredefinedFormats);
$stuff=array_combine($keys, $keys);
return $stuff+["" => "Custom Format..."];
}
public static function barcodeDimensions($barcode_type = 'QRCODE')
{
if ($barcode_type == 'C128') {
$size['height'] = '-1';
$size['width'] = '-10';
} elseif ($barcode_type == 'PDF417') {
$size['height'] = '-3';
$size['width'] = '-10';
} else {
$size['height'] = '-3';
$size['width'] = '-3';
}
return $size;
}
public static function generateRandomString($length = 10)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
/**
* This nasty little method gets the low inventory info for the
* alert dropdown
**/
public static function checkLowInventory()
{
$consumables = Consumable::with('users')->whereNotNull('min_amt')->get();
$accessories = Accessory::with('users')->whereNotNull('min_amt')->get();
$components = Component::with('assets')->whereNotNull('min_amt')->get();
$avail_consumables = 0;
$items_array = array();
$all_count = 0;
foreach ($consumables as $consumable) {
$avail = $consumable->numRemaining();
if ($avail < ($consumable->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($consumable->total_qty > 0) {
$percent = number_format((($consumable->numRemaining() / $consumable->total_qty) * 100), 0);
} else {
$percent = 100;
}
$items_array[$all_count]['id'] = $consumable->id;
$items_array[$all_count]['name'] = $consumable->name;
$items_array[$all_count]['type'] = 'consumables';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$consumable->numRemaining();
$items_array[$all_count]['min_amt']=$consumable->min_amt;
$all_count++;
}
}
foreach ($accessories as $accessory) {
$avail = $accessory->numRemaining();
if ($avail < ($accessory->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($accessory->total_qty > 0) {
$percent = number_format((($accessory->numRemaining() / $accessory->total_qty) * 100), 0);
} else {
$percent = 100;
}
$items_array[$all_count]['id'] = $accessory->id;
$items_array[$all_count]['name'] = $accessory->name;
$items_array[$all_count]['type'] = 'accessories';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$accessory->numRemaining();
$items_array[$all_count]['min_amt']=$accessory->min_amt;
$all_count++;
}
}
foreach ($components as $component) {
$avail = $component->numRemaining();
if ($avail < ($component->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
if ($component->total_qty > 0) {
$percent = number_format((($component->numRemaining() / $component->total_qty) * 100), 0);
} else {
$percent = 100;
}
$items_array[$all_count]['id'] = $component->id;
$items_array[$all_count]['name'] = $component->name;
$items_array[$all_count]['type'] = 'components';
$items_array[$all_count]['percent'] = $percent;
$items_array[$all_count]['remaining']=$component->numRemaining();
$items_array[$all_count]['min_amt']=$component->min_amt;
$all_count++;
}
}
return $items_array;
}
public static function checkUploadIsImage($file)
{
// Check if the file is an image, so we can show a preview
$finfo = @finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$filetype = @finfo_file($finfo, $file);
finfo_close($finfo);
if (($filetype=="image/jpeg") || ($filetype=="image/jpg") || ($filetype=="image/png") || ($filetype=="image/bmp") || ($filetype=="image/gif")) {
return $filetype;
}
return false;
}
/**
* Walks through the permissions in the permissions config file and determines if
* permissions are granted based on a $selected_arr array.
*
* The $permissions array is a multidimensional array broke down by section.
* (Licenses, Assets, etc)
*
* The $selected_arr should be a flattened array that contains just the
* corresponding permission name and a true or false boolean to determine
* if that group/user has been granted that permission.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @param array $permissions
* @param array $selected_arr
* @since [v1.0]
* @return Array
*/
public static function selectedPermissionsArray($permissions, $selected_arr = array())
{
$permissions_arr = array();
foreach ($permissions as $permission) {
for ($x = 0; $x < count($permission); $x++) {
$permission_name = $permission[$x]['permission'];
if ($permission[$x]['display'] === true) {
if ($selected_arr) {
if (array_key_exists($permission_name,$selected_arr)) {
$permissions_arr[$permission_name] = $selected_arr[$permission_name];
} else {
$permissions_arr[$permission_name] = '0';
}
} else {
$permissions_arr[$permission_name] = '0';
}
}
}
}
return $permissions_arr;
}
}
+669
View File
@@ -0,0 +1,669 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Setting;
use App\Models\User;
use Carbon\Carbon;
use Config;
use DB;
use Input;
use Lang;
use Mail;
use Redirect;
use Slack;
use Str;
use View;
use Auth;
use Request;
/** This controller handles all actions related to Accessories for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class AccessoriesController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the accessories listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see AccessoriesController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex(Request $request)
{
return View::make('accessories/index');
}
/**
* Returns a view with a form to create a new Accessory.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @return View
*/
public function getCreate(Request $request)
{
// Show the page
$category_list = Helper::categoryList('accessory');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
return View::make('accessories/edit')
->with('accessory', new Accessory)
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list);
}
/**
* Validate and save new Accessory from form post
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @return Redirect
*/
public function postCreate(Request $request)
{
// create a new model instance
$accessory = new Accessory();
// Update the accessory data
$accessory->name = e(Input::get('name'));
$accessory->category_id = e(Input::get('category_id'));
$accessory->location_id = e(Input::get('location_id'));
$accessory->min_amt = e(Input::get('min_amt'));
$accessory->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$accessory->order_number = e(Input::get('order_number'));
if (e(Input::get('purchase_date')) == '') {
$accessory->purchase_date = null;
} else {
$accessory->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$accessory->purchase_cost = null;
} else {
$accessory->purchase_cost = e(Input::get('purchase_cost'));
}
$accessory->qty = e(Input::get('qty'));
$accessory->user_id = Auth::user()->id;
// Was the accessory created?
if ($accessory->save()) {
// Redirect to the new accessory page
return redirect()->to("admin/accessories")->with('success', trans('admin/accessories/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
/**
* Return view for the Accessory update form, prepopulated with existing data
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return View
*/
public function getEdit(Request $request, $accessoryId = null)
{
// Check if the accessory exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
$category_list = Helper::categoryList('accessory');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
return View::make('accessories/edit', compact('accessory'))
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list);
}
/**
* Save edited Accessory from form post
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return Redirect
*/
public function postEdit(Request $request, $accessoryId = null)
{
// Check if the blog post exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
// Update the accessory data
$accessory->name = e(Input::get('name'));
if (e(Input::get('location_id')) == '') {
$accessory->location_id = null;
} else {
$accessory->location_id = e(Input::get('location_id'));
}
$accessory->min_amt = e(Input::get('min_amt'));
$accessory->category_id = e(Input::get('category_id'));
$accessory->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$accessory->order_number = e(Input::get('order_number'));
if (e(Input::get('purchase_date')) == '') {
$accessory->purchase_date = null;
} else {
$accessory->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$accessory->purchase_cost = null;
} else {
$accessory->purchase_cost = e(Input::get('purchase_cost'));
}
$accessory->qty = e(Input::get('qty'));
// Was the accessory created?
if ($accessory->save()) {
// Redirect to the new accessory page
return redirect()->to("admin/accessories")->with('success', trans('admin/accessories/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
/**
* Delete the given accessory.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return Redirect
*/
public function getDelete(Request $request, $accessoryId)
{
// Check if the blog post exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
if ($accessory->hasUsers() > 0) {
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers())));
} else {
$accessory->delete();
// Redirect to the locations management page
return redirect()->to('admin/accessories')->with('success', trans('admin/accessories/message.delete.success'));
}
}
/**
* Returns a view that invokes the ajax table which contains
* the content for the accessory detail view, which is generated in getDataView.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @see AccessoriesController::getDataView() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getView(Request $request, $accessoryID = null)
{
$accessory = Accessory::find($accessoryID);
if (isset($accessory->id)) {
if (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
} else {
return View::make('accessories/view', compact('accessory'));
}
} else {
// 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 the form to checkout an Accessory to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return View
*/
public function getCheckout(Request $request, $accessoryId)
{
// Check if the accessory exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the accessory management page with error
return redirect()->to('accessories')->with('error', trans('admin/accessories/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
// Get the dropdown of users and then pass it to the checkout view
$users_list = Helper::usersList();
return View::make('accessories/checkout', compact('accessory'))->with('users_list', $users_list);
}
/**
* Save the Accessory checkout information.
*
* If Slack is enabled and/or asset acceptance is enabled, it will also
* trigger a Slack message and send an email.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return Redirect
*/
public function postCheckout(Request $request, $accessoryId)
{
// Check if the accessory exists
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the accessory management page with error
return redirect()->to('accessories')->with('error', trans('admin/accessories/message.user_not_found'));
} elseif (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
if (!$user = User::find(Input::get('assigned_to'))) {
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.not_found'));
}
// Update the accessory data
$accessory->assigned_to = e(Input::get('assigned_to'));
$accessory->users()->attach($accessory->id, array(
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::user()->id,
'assigned_to' => e(Input::get('assigned_to'))));
$logaction = new Actionlog();
$logaction->accessory_id = $accessory->id;
$logaction->asset_id = 0;
$logaction->checkedout_to = $accessory->assigned_to;
$logaction->asset_type = 'accessory';
$logaction->location_id = $user->location_id;
$logaction->user_id = Auth::user()->id;
$logaction->note = e(Input::get('note'));
$admin_user = Auth::user();
$settings = Setting::getSettings();
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'Checked Out:',
'value' => strtoupper($logaction->asset_type).' <'.config('app.url').'/admin/accessories/'.$accessory->id.'/view'.'|'.$accessory->name.'> checked out to <'.config('app.url').'/admin/users/'.$user->id.'/view|'.$user->fullName().'> by <'.config('app.url').'/admin/users/'.$admin_user->id.'/view'.'|'.$admin_user->fullName().'>.'
],
[
'title' => 'Note:',
'value' => e($logaction->note)
],
]
])->send('Accessory Checked Out');
} catch (Exception $e) {
}
}
$log = $logaction->logaction('checkout');
$accessory_user = DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
$data['log_id'] = $logaction->id;
$data['eula'] = $accessory->getEula();
$data['first_name'] = $user->first_name;
$data['item_name'] = $accessory->name;
$data['checkout_date'] = $logaction->created_at;
$data['item_tag'] = '';
$data['expected_checkin'] = '';
$data['note'] = $logaction->note;
$data['require_acceptance'] = $accessory->requireAcceptance();
if (($accessory->requireAcceptance()=='1') || ($accessory->getEula())) {
Mail::send('emails.accept-accessory', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->subject('Confirm accessory delivery');
});
}
// Redirect to the new accessory page
return redirect()->to("admin/accessories")->with('success', trans('admin/accessories/message.checkout.success'));
}
/**
* Check the accessory back into inventory
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return View
**/
public function getCheckin(Request $request, $accessoryUserId = null, $backto = null)
{
// Check if the accessory exists
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
// Redirect to the accessory management page with error
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.not_found'));
}
$accessory = Accessory::find($accessory_user->accessory_id);
if (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
} else {
return View::make('accessories/checkin', compact('accessory'))->with('backto', $backto);
}
}
/**
* Check in the item so that it can be checked out again to someone else
*
* @uses Accessory::checkin_email() to determine if an email can and should be sent
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
* @return Redirect
**/
public function postCheckin(Request $request, $accessoryUserId = null, $backto = null)
{
// Check if the accessory exists
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
// Redirect to the accessory management page with error
return redirect()->to('admin/accessories')->with('error', trans('admin/accessories/message.not_found'));
}
$accessory = Accessory::find($accessory_user->accessory_id);
if (!Company::isCurrentUserHasAccess($accessory)) {
return redirect()->to('admin/accessories')->with('error', trans('general.insufficient_permissions'));
}
$logaction = new Actionlog();
$logaction->checkedout_to = e($accessory_user->assigned_to);
$return_to = e($accessory_user->assigned_to);
$admin_user = Auth::user();
// Was the accessory updated?
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
$logaction->accessory_id = e($accessory->id);
$logaction->location_id = null;
$logaction->asset_type = 'accessory';
$logaction->user_id = e($admin_user->id);
$logaction->note = e(Input::get('note'));
$settings = Setting::getSettings();
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => e($settings->botname),
'channel' => e($settings->slack_channel),
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'Checked In:',
'value' => strtoupper($logaction->asset_type).' <'.config('app.url').'/admin/accessories/'.e($accessory->id).'/view'.'|'.e($accessory->name).'> checked in by <'.config('app.url').'/admin/users/'.e($admin_user->id).'/view'.'|'.e($admin_user->fullName()).'>.'
],
[
'title' => 'Note:',
'value' => e($logaction->note)
],
]
])->send('Accessory Checked In');
} catch (Exception $e) {
}
}
$log = $logaction->logaction('checkin from');
if (!is_null($accessory_user->assigned_to)) {
$user = User::find($accessory_user->assigned_to);
}
$data['log_id'] = $logaction->id;
$data['first_name'] = e($user->first_name);
$data['item_name'] = e($accessory->name);
$data['checkin_date'] = e($logaction->created_at);
$data['item_tag'] = '';
$data['note'] = e($logaction->note);
if (($accessory->checkin_email()=='1')) {
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->subject('Confirm Accessory Checkin');
});
}
if ($backto=='user') {
return redirect()->to("admin/users/".$return_to.'/view')->with('success', trans('admin/accessories/message.checkin.success'));
} else {
return redirect()->to("admin/accessories/".$accessory->id."/view")->with('success', trans('admin/accessories/message.checkin.success'));
}
}
// Redirect to the accessory management page with error
return redirect()->to("admin/accessories")->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)",
* "companyName": "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 int $accessoryId
* @return string JSON containing accessories and their associated atrributes.
**/
public function getDatatable(Request $request)
{
$accessories = Accessory::select('accessories.*')->with('category', 'company')
->whereNull('accessories.deleted_at');
if (Input::has('search')) {
$accessories = $accessories->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['name','min_amt','order_number','purchase_date','purchase_cost','companyName','category'];
$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 'companyName':
$accessories = $accessories->OrderCompany($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) {
$actions = '<nobr><a href="'.route('checkout/accessory', $accessory->id).'" style="margin-right:5px;" class="btn btn-info btn-sm" '.(($accessory->numRemaining() > 0 ) ? '' : ' disabled').'>'.trans('general.checkout').'</a><a href="'.route('update/accessory', $accessory->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/accessory', $accessory->id).'" data-content="'.trans('admin/accessories/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($accessory->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></nobr>';
$company = $accessory->company;
$rows[] = array(
'name' => '<a href="'.url('admin/accessories/'.$accessory->id).'/view">'. $accessory->name.'</a>',
'category' => ($accessory->category) ? (string)link_to('admin/settings/categories/'.$accessory->category->id.'/view', $accessory->category->name) : '',
'qty' => e($accessory->qty),
'order_number' => e($accessory->order_number),
'min_amt' => e($accessory->min_amt),
'location' => ($accessory->location) ? e($accessory->location->name): '',
'purchase_date' => e($accessory->purchase_date),
'purchase_cost' => number_format($accessory->purchase_cost, 2),
'numRemaining' => $accessory->numRemaining(),
'actions' => $actions,
'companyName' => is_null($company) ? '' : e($company->name)
);
}
$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 = '<a href="'.route('checkin/accessory', $user->pivot->id).'" class="btn btn-info btn-sm">Checkin</a>';
$rows[] = array(
'name' =>(string) link_to('/admin/users/'.$user->id.'/view', e($user->fullName())),
'actions' => $actions
);
}
$data = array('total'=>$count, 'rows'=>$rows);
return $data;
}
}
@@ -0,0 +1,473 @@
<?php
namespace App\Http\Controllers;
use App\Models\AssetMaintenance;
use Carbon\Carbon;
use App\Models\Company;
use DB;
use Input;
use Lang;
use Log;
use Mail;
use Redirect;
use Response;
use Slack;
use Str;
use App\Models\Supplier;
use TCPDF;
use Validator;
use View;
use App\Models\Setting;
use App\Models\Asset;
use App\Helpers\Helper;
use Auth;
/**
* This controller handles all actions related to Asset Maintenance for
* the Snipe-IT Asset Management application.
*
* @version v2.0
*/
class AssetMaintenancesController extends Controller
{
/**
* Checks for permissions for this action.
*
* @todo This should be replaced with middleware and/or policies
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return View
*/
private static function getInsufficientPermissionsRedirect()
{
return redirect()->route('asset_maintenances')
->with('error', trans('general.insufficient_permissions'));
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the asset maintenances listing, which is generated in getDatatable.
*
* @todo This should be replaced with middleware and/or policies
* @see AssetMaintenancesController::getDatatable() method that generates the JSON response
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return View
*/
public function getIndex()
{
return View::make('asset_maintenances/index');
}
/**
* Generates the JSON response for asset maintenances listing view.
*
* @see AssetMaintenancesController::getIndex() method that generates view
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return String JSON
*/
public function getDatatable()
{
$maintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company','admin')
->withTrashed();
if (Input::has('search')) {
$maintenances = $maintenances->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','title','asset_maintenance_time','asset_maintenance_type','cost','start_date','completion_date','notes','user_id'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e(Input::get('sort')) : 'created_at';
switch ($sort) {
case 'user_id':
$maintenances = $maintenances->OrderAdmin($order);
break;
default:
$maintenances = $maintenances->orderBy($sort, $order);
break;
}
$maintenancesCount = $maintenances->count();
$maintenances = $maintenances->skip($offset)->take($limit)->get();
$rows = array();
$settings = Setting::getSettings();
foreach ($maintenances as $maintenance) {
$actions = '<nobr><a href="'.route('update/asset_maintenance', $maintenance->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/asset_maintenance', $maintenance->id).'" data-content="'.trans('admin/asset_maintenances/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($maintenance->title).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></nobr>';
if (($maintenance->cost) && ($maintenance->asset->assetloc) && ($maintenance->asset->assetloc->currency!='')) {
$maintenance_cost = $maintenance->asset->assetloc->currency.$maintenance->cost;
} else {
$maintenance_cost = $settings->default_currency.$maintenance->cost;
}
$company = $maintenance->asset->company;
$rows[] = array(
'id' => $maintenance->id,
'asset_name' => (string)link_to('/hardware/'.$maintenance->asset->id.'/view', $maintenance->asset->showAssetName()) ,
'title' => $maintenance->title,
'notes' => $maintenance->notes,
'supplier' => $maintenance->supplier->name,
'cost' => $maintenance_cost,
'asset_maintenance_type' => e($maintenance->asset_maintenance_type),
'start_date' => $maintenance->start_date,
'asset_maintenance_time' => $maintenance->asset_maintenance_time,
'completion_date' => $maintenance->completion_date,
'user_id' => ($maintenance->admin) ? (string)link_to('/admin/users/'.$maintenance->admin->id.'/view', $maintenance->admin->fullName()) : '',
'actions' => $actions,
'companyName' => is_null($company) ? '' : $company->name
);
}
$data = array('total' => $maintenancesCount, 'rows' => $rows);
return $data;
}
/**
* Returns a form view to create a new asset maintenance.
*
* @see AssetMaintenancesController::postCreate() method that stores the data
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return mixed
*/
public function getCreate($assetId = null)
{
// Prepare Asset Maintenance Type List
$assetMaintenanceType = [
'' => 'Select an asset maintenance type',
] + AssetMaintenance::getImprovementOptions();
// Mark the selected asset, if it came in
$selectedAsset = $assetId;
$assets = Helper::detailedAssetList();
$supplier_list = Helper::suppliersList();
// Render the view
return View::make('asset_maintenances/edit')
->with('asset_list', $assets)
->with('selectedAsset', $selectedAsset)
->with('supplier_list', $supplier_list)
->with('assetMaintenanceType', $assetMaintenanceType)
->with('assetMaintenance', new AssetMaintenance);
}
/**
* Validates and stores the new asset maintenance
*
* @see AssetMaintenancesController::getCreate() method for the form
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
* @since [v1.8]
* @return mixed
*/
public function postCreate()
{
// get the POST data
$new = Input::all();
// create a new model instance
$assetMaintenance = new AssetMaintenance();
if (e(Input::get('supplier_id')) == '') {
$assetMaintenance->supplier_id = null;
} else {
$assetMaintenance->supplier_id = e(Input::get('supplier_id'));
}
if (e(Input::get('is_warranty')) == '') {
$assetMaintenance->is_warranty = 0;
} else {
$assetMaintenance->is_warranty = e(Input::get('is_warranty'));
}
if (e(Input::get('cost')) == '') {
$assetMaintenance->cost = '';
} else {
$assetMaintenance->cost = e(Input::get('cost'));
}
if (e(Input::get('notes')) == '') {
$assetMaintenance->notes = null;
} else {
$assetMaintenance->notes = e(Input::get('notes'));
}
$asset = Asset::find(e(Input::get('asset_id')));
if (!Company::isCurrentUserHasAccess($asset)) {
return static::getInsufficientPermissionsRedirect();
}
// Save the asset maintenance data
$assetMaintenance->asset_id = e(Input::get('asset_id'));
$assetMaintenance->asset_maintenance_type = e(Input::get('asset_maintenance_type'));
$assetMaintenance->title = e(Input::get('title'));
$assetMaintenance->start_date = e(Input::get('start_date'));
$assetMaintenance->completion_date = e(Input::get('completion_date'));
$assetMaintenance->user_id = Auth::user()->id;
if (( $assetMaintenance->completion_date == "" )
|| ( $assetMaintenance->completion_date == "0000-00-00" )
) {
$assetMaintenance->completion_date = null;
}
if (( $assetMaintenance->completion_date !== "" )
&& ( $assetMaintenance->completion_date !== "0000-00-00" )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
// Was the asset maintenance created?
if ($assetMaintenance->save()) {
// Redirect to the new asset maintenance page
return redirect()->to("admin/asset_maintenances")
->with('success', trans('admin/asset_maintenances/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
}
/**
* Returns a form view to edit a selected asset maintenance.
*
* @see AssetMaintenancesController::postEdit() method that stores the data
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @param int $assetMaintenanceId
* @version v1.0
* @since [v1.8]
* @return mixed
*/
public function getEdit($assetMaintenanceId = null)
{
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the improvement management page
return redirect()->to('admin/asset_maintenances')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
if ($assetMaintenance->completion_date == '0000-00-00') {
$assetMaintenance->completion_date = null;
}
if ($assetMaintenance->start_date == '0000-00-00') {
$assetMaintenance->start_date = null;
}
if ($assetMaintenance->cost == '0.00') {
$assetMaintenance->cost = null;
}
// Prepare Improvement Type List
$assetMaintenanceType = [
'' => 'Select an improvement type',
] + AssetMaintenance::getImprovementOptions();
$assets = Company::scopeCompanyables(Asset::all(), 'assets.company_id')->lists('detailed_name', 'id');
// Get Supplier List
$supplier_list = Helper::suppliersList();
// Render the view
return View::make('asset_maintenances/edit')
->with('asset_list', $assets)
->with('selectedAsset', null)
->with('supplier_list', $supplier_list)
->with('assetMaintenanceType', $assetMaintenanceType)
->with('assetMaintenance', $assetMaintenance);
}
/**
* Validates and stores an update to an asset maintenance
*
* @see AssetMaintenancesController::postEdit() method that stores the data
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @param int $assetMaintenanceId
* @version v1.0
* @since [v1.8]
* @return mixed
*/
public function postEdit($assetMaintenanceId = null)
{
// get the POST data
$new = Input::all();
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->to('admin/asset_maintenances')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
if (e(Input::get('supplier_id')) == '') {
$assetMaintenance->supplier_id = null;
} else {
$assetMaintenance->supplier_id = e(Input::get('supplier_id'));
}
if (e(Input::get('is_warranty')) == '') {
$assetMaintenance->is_warranty = 0;
} else {
$assetMaintenance->is_warranty = e(Input::get('is_warranty'));
}
if (e(Input::get('cost')) == '') {
$assetMaintenance->cost = '';
} else {
$assetMaintenance->cost = e(Input::get('cost'));
}
if (e(Input::get('notes')) == '') {
$assetMaintenance->notes = null;
} else {
$assetMaintenance->notes = e(Input::get('notes'));
}
$asset = Asset::find(e(Input::get('asset_id')));
if (!Company::isCurrentUserHasAccess($asset)) {
return static::getInsufficientPermissionsRedirect();
}
// Save the asset maintenance data
$assetMaintenance->asset_id = e(Input::get('asset_id'));
$assetMaintenance->asset_maintenance_type = e(Input::get('asset_maintenance_type'));
$assetMaintenance->title = e(Input::get('title'));
$assetMaintenance->start_date = e(Input::get('start_date'));
$assetMaintenance->completion_date = e(Input::get('completion_date'));
if (( $assetMaintenance->completion_date == "" )
|| ( $assetMaintenance->completion_date == "0000-00-00" )
) {
$assetMaintenance->completion_date = null;
if (( $assetMaintenance->asset_maintenance_time !== 0 )
|| ( !is_null($assetMaintenance->asset_maintenance_time) )
) {
$assetMaintenance->asset_maintenance_time = null;
}
}
if (( $assetMaintenance->completion_date !== "" )
&& ( $assetMaintenance->completion_date !== "0000-00-00" )
&& ( $assetMaintenance->start_date !== "" )
&& ( $assetMaintenance->start_date !== "0000-00-00" )
) {
$startDate = Carbon::parse($assetMaintenance->start_date);
$completionDate = Carbon::parse($assetMaintenance->completion_date);
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
}
// Was the asset maintenance created?
if ($assetMaintenance->save()) {
// Redirect to the new asset maintenance page
return redirect()->to("admin/asset_maintenances")
->with('success', trans('admin/asset_maintenances/message.create.success'));
}
return redirect()->back() ->withInput()->withErrors($assetMaintenance->getErrors());
}
/**
* Delete an asset maintenance
*
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @param int $assetMaintenanceId
* @version v1.0
* @since [v1.8]
* @return mixed
*/
public function getDelete($assetMaintenanceId)
{
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->to('admin/asset_maintenances')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
// Delete the asset maintenance
$assetMaintenance->delete();
// Redirect to the asset_maintenance management page
return redirect()->to('admin/asset_maintenances')
->with('success', trans('admin/asset_maintenances/message.delete.success'));
}
/**
* View an asset maintenance
*
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @param int $assetMaintenanceId
* @version v1.0
* @since [v1.8]
* @return View
*/
public function getView($assetMaintenanceId)
{
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->to('admin/asset_maintenances')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
return View::make('asset_maintenances/view')->with('assetMaintenance', $assetMaintenance);
}
}
+550
View File
@@ -0,0 +1,550 @@
<?php
namespace App\Http\Controllers;
use Image;
use Input;
use Lang;
use App\Models\AssetModel;
use Redirect;
use App\Models\Setting;
use Auth;
use DB;
use App\Models\Depreciation;
use App\Models\Manufacturer;
use Str;
use Validator;
use View;
use App\Models\Asset;
use App\Models\Company;
use Config;
use App\Helpers\Helper;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* This class controls all actions related to asset models for
* the Snipe-IT Asset Management application.
*
* @version v1.0
* @author [A. Gianotto] [<snipe@snipe.net>]
*/
class AssetModelsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* 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
*/
public function getIndex()
{
// Show the page
return View::make('models/index');
}
/**
* Returns a view containing the asset model creation form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getCreate()
{
// Show the page
$depreciation_list = Helper::depreciationList();
$manufacturer_list = Helper::manufacturerList();
$category_list = Helper::categoryList('asset');
return View::make('models/edit')
->with('category_list', $category_list)
->with('depreciation_list', $depreciation_list)
->with('manufacturer_list', $manufacturer_list)
->with('model', new AssetModel);
}
/**
* Validate and process the new Asset Model data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
// Create a new asset model
$model = new AssetModel;
if (e(Input::get('depreciation_id')) == '') {
$model->depreciation_id = 0;
} else {
$model->depreciation_id = e(Input::get('depreciation_id'));
}
if (e(Input::get('eol')) == '') {
$model->eol = 0;
} else {
$model->eol = e(Input::get('eol'));
}
// Save the model data
$model->name = e(Input::get('name'));
$model->modelno = e(Input::get('modelno'));
$model->manufacturer_id = e(Input::get('manufacturer_id'));
$model->category_id = e(Input::get('category_id'));
$model->note = e(Input::get('note'));
$model->user_id = Auth::user()->id;
if (Input::get('custom_fieldset')!='') {
$model->fieldset_id = e(Input::get('custom_fieldset'));
}
//$model->show_mac_address = e(Input::get('show_mac_address', '0'));
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);
$model->image = $file_name;
}
// Was it created?
if ($model->save()) {
// Redirect to the new model page
return redirect()->to("hardware/models")->with('success', trans('admin/models/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($model->getErrors());
}
/**
* Validates and stores new Asset Model data created from the
* modal form on the Asset Creation view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @return String JSON
*/
public function store()
{
//COPYPASTA!!!! FIXME
$model = new AssetModel;
$settings=Input::all();
$settings['eol']=0;
$model->name=e(Input::get('name'));
$model->manufacturer_id = e(Input::get('manufacturer_id'));
$model->category_id = e(Input::get('category_id'));
$model->modelno = e(Input::get('modelno'));
$model->user_id = Auth::user()->id;
$model->note = e(Input::get('note'));
$model->eol=0;
if (Input::get('fieldset_id')=='') {
$model->fieldset_id = null;
} else {
$model->fieldset_id = e(Input::get('fieldset_id'));
}
if ($model->save()) {
return JsonResponse::create($model);
} else {
return JsonResponse::create(["error" => "Failed validation: ".print_r($model->getErrors()->all('<li>:message</li>'), true)], 500);
}
}
/**
* Returns a view containing the asset model edit form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
public function getEdit($modelId = null)
{
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
// Redirect to the model management page
return redirect()->to('assets/models')->with('error', trans('admin/models/message.does_not_exist'));
}
$depreciation_list = Helper::depreciationList();
$manufacturer_list = Helper::manufacturerList();
$category_list = Helper::categoryList('asset');
$view = View::make('models/edit', compact('model'));
$view->with('category_list', $category_list);
$view->with('depreciation_list', $depreciation_list);
$view->with('manufacturer_list', $manufacturer_list);
return $view;
}
/**
* Validates and processes form data from the edit
* Asset Model form based on the model ID passed.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
*/
public function postEdit($modelId = null)
{
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
// Redirect to the models management page
return redirect()->to('admin/models')->with('error', trans('admin/models/message.does_not_exist'));
}
if (e(Input::get('depreciation_id')) == '') {
$model->depreciation_id = 0;
} else {
$model->depreciation_id = e(Input::get('depreciation_id'));
}
if (e(Input::get('eol')) == '') {
$model->eol = 0;
} else {
$model->eol = e(Input::get('eol'));
}
// Update the model data
$model->name = e(Input::get('name'));
$model->modelno = e(Input::get('modelno'));
$model->manufacturer_id = e(Input::get('manufacturer_id'));
$model->category_id = e(Input::get('category_id'));
$model->note = e(Input::get('note'));
if (Input::get('custom_fieldset')=='') {
$model->fieldset_id = null;
} else {
$model->fieldset_id = e(Input::get('custom_fieldset'));
}
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);
$model->image = $file_name;
}
if (Input::get('image_delete') == 1 && Input::file('image') == "") {
$model->image = null;
}
// Was it created?
if ($model->save()) {
// Redirect to the new model page
return redirect()->to("hardware/models")->with('success', trans('admin/models/message.update.success'));
} else {
return redirect()->back()->withInput()->withErrors($model->getErrors());
}
// Redirect to the model create page
return redirect()->to("hardware/models/$modelId/edit")->with('error', trans('admin/models/message.update.error'));
}
/**
* Validate and delete the given Asset Model. An Asset Model
* cannot be deleted if there are associated assets.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
*/
public function getDelete($modelId)
{
// Check if the model exists
if (is_null($model = AssetModel::find($modelId))) {
// Redirect to the blogs management page
return redirect()->to('hardware/models')->with('error', trans('admin/models/message.not_found'));
}
if ($model->assets->count() > 0) {
// Throw an error that this model is associated with assets
return redirect()->to('hardware/models')->with('error', trans('admin/models/message.assoc_users'));
} else {
// Delete the model
$model->delete();
// Redirect to the models management page
return redirect()->to('hardware/models')->with('success', trans('admin/models/message.delete.success'));
}
}
/**
* Restore a given Asset Model (mark as un-deleted)
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return Redirect
*/
public function getRestore($modelId = null)
{
// Get user information
$model = AssetModel::withTrashed()->find($modelId);
if (isset($model->id)) {
// Restore the model
$model->restore();
// Prepare the success message
$success = trans('admin/models/message.restore.success');
// Redirect back
return redirect()->back()->with('success', $success);
} else {
return redirect()->back()->with('error', trans('admin/models/message.not_found'));
}
}
/**
* Get the model information to present to the model view page
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
public function getView($modelId = null)
{
$model = AssetModel::withTrashed()->find($modelId);
if (isset($model->id)) {
return View::make('models/view', compact('model'));
} else {
// Prepare the error message
$error = trans('admin/models/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('models')->with('error', $error);
}
}
/**
* Get the clone page to clone a model
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $modelId
* @return View
*/
public function getClone($modelId = null)
{
// Check if the model exists
if (is_null($model_to_clone = AssetModel::find($modelId))) {
// Redirect to the model management page
return redirect()->to('assets/models')->with('error', trans('admin/models/message.does_not_exist'));
}
$model = clone $model_to_clone;
$model->id = null;
// Show the page
$depreciation_list = Helper::depreciationList();
$manufacturer_list = Helper::manufacturerList();
$category_list = Helper::categoryList('asset');
$view = View::make('models/edit');
$view->with('category_list', $category_list);
$view->with('depreciation_list', $depreciation_list);
$view->with('manufacturer_list', $manufacturer_list);
$view->with('model', $model);
$view->with('clone_model', $model_to_clone);
return $view;
}
/**
* Get the custom fields form
*
* @author [B. Wetherington] [<uberbrady@gmail.com>]
* @since [v2.0]
* @param int $modelId
* @return View
*/
public function getCustomFields($modelId)
{
$model=AssetModel::find($modelId);
return View::make("models.custom_fields_form")->with("model", $model);
}
/**
* Get the JSON response to populate the data tables on the
* Asset Model listing page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @param string $status
* @return String JSON
*/
public function getDatatable($status = null)
{
$models = AssetModel::with('category', 'assets', 'depreciation');
switch ($status) {
case 'Deleted':
$models->withTrashed()->Deleted();
break;
}
if (Input::has('search')) {
$models = $models->TextSearch(Input::get('search'));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','modelno'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e(Input::get('sort')) : 'created_at';
$models = $models->orderBy($sort, $order);
$modelCount = $models->count();
$models = $models->skip($offset)->take($limit)->get();
$rows = array();
foreach ($models as $model) {
if ($model->deleted_at == '') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('clone/model', $model->id).'" class="btn btn-info btn-sm" title="Clone Model" data-toggle="tooltip"><i class="fa fa-clone"></i></a> <a href="'.route('update/model', $model->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/model', $model->id).'" data-content="'.trans('admin/models/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($model->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
} else {
$actions = '<a href="'.route('restore/model', $model->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
}
$rows[] = array(
'id' => $model->id,
'manufacturer' => (string)link_to('/admin/settings/manufacturers/'.$model->manufacturer->id.'/view', $model->manufacturer->name),
'name' => (string)link_to('/hardware/models/'.$model->id.'/view', $model->name),
'image' => ($model->image!='') ? '<img src="'.config('app.url').'/uploads/models/'.$model->image.'" height=50 width=50>' : '',
'modelnumber' => $model->modelno,
'numassets' => $model->assets->count(),
'depreciation' => (($model->depreciation)&&($model->depreciation->id > 0)) ? $model->depreciation->name.' ('.$model->depreciation->months.')' : trans('general.no_depreciation'),
'category' => ($model->category) ? $model->category->name : '',
'eol' => ($model->eol) ? $model->eol.' '.trans('general.months') : '',
'note' => $model->getNote(),
'actions' => $actions
);
}
$data = array('total' => $modelCount, 'rows' => $rows);
return $data;
}
/**
* Get the asset information to present to the model view detail page
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @param int $modelId
* @return String JSON
*/
public function getDataView($modelID)
{
$assets = Asset::where('model_id', '=', $modelID)->with('company');
if (Input::has('search')) {
$assets = $assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['name', 'serial','asset_tag'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e(Input::get('sort')) : 'created_at';
$assets = $assets->orderBy($sort, $order);
$assetsCount = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
$rows = array();
foreach ($assets as $asset) {
$actions = '';
if ($asset->assetstatus) {
if ($asset->assetstatus->deployable != 0) {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) {
$actions = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>';
} else {
$actions = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>';
}
}
}
$rows[] = array(
'id' => $asset->id,
'name' => (string)link_to('/hardware/'.$asset->id.'/view', $asset->showAssetName()),
'asset_tag' => (string)link_to('hardware/'.$asset->id.'/view', $asset->asset_tag),
'serial' => $asset->serial,
'assigned_to' => ($asset->assigned_to) ? (string)link_to('/admin/users/'.$asset->assigned_to.'/view', $asset->assigneduser->fullName()) : '',
'actions' => $actions,
'companyName' => Company::getName($asset)
);
}
$data = array('total' => $assetsCount, 'rows' => $rows);
return $data;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,198 @@
<?php
namespace App\Http\Controllers\Auth;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use App\Models\Setting;
use App\Models\Ldap;
use App\Models\User;
use Auth;
use Config;
use Illuminate\Http\Request;
use Input;
use Redirect;
use Log;
use View;
/**
* This controller handles authentication for the user, including local
* database users and LDAP users.
*
* @todo Move LDAP methods into user model for better separation of concerns.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @version v1.0
*/
class AuthController extends Controller
{
use ThrottlesLogins;
// This tells the auth controller to use username instead of email address
protected $username = 'username';
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
function showLoginForm()
{
// Is the user logged in?
if (Auth::check()) {
return redirect()->intended('dashboard');
}
// Show the page
return View::make('auth.login');
}
/**
* Account sign in form processing.
*
* @return Redirect
*/
public function login(Request $request)
{
$validator = $this->validator(Input::all());
if ($validator->fails()) {
return redirect()->back()->withInput()->withErrors($validator);
}
// Should we even check for LDAP users?
if (Setting::getSettings()->ldap_enabled=='1') {
LOG::debug("LDAP is enabled.");
// Check if the user exists in the database
$user = User::where('username', '=', Input::get('username'))->whereNull('deleted_at')->first();
LOG::debug("Local auth lookup complete");
try {
Ldap::findAndBindUserLdap($request->input('username'), $request->input('password'));
LOG::debug("Binding user to LDAP.");
} catch (\Exception $e) {
LOG::debug("User ".Input::get('username').' did not authenticate successfully against LDAP.');
//$ldap_error = $e->getMessage();
// return redirect()->back()->withInput()->with('error',$e->getMessage());
}
// The user does not exist in the database. Try to get them from LDAP.
// If user does not exist and authenticates sucessfully with LDAP we
// will create it on the fly and sign in with default permissions
if (!$user) {
LOG::debug("Local user ".Input::get('username')." does not exist");
try {
if ($userattr = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password'))) {
LOG::debug("Creating local user ".Input::get('username'));
if ($newuser = Ldap::createUserFromLdap($userattr)) {
LOG::debug("Local user created..");
} else {
LOG::debug("Could not create local user.");
}
} else {
LOG::debug("User did not authenticate correctly against LDAP. No local user was created.");
}
} catch (\Exception $e) {
return redirect()->back()->withInput()->with('error',$e->getMessage());
}
// If the user exists and they were imported from LDAP already
} else {
LOG::debug("Local user ".Input::get('username')." exists in database. Authenticating existing user against LDAP.");
if ($ldap_user = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password'))) {
$ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user);
LOG::debug("Valid LDAP login. Updating the local data.");
$user->password = bcrypt($request->input('password'));
$user->email = $ldap_attr['email'];
$user->first_name = $ldap_attr['firstname'];
$user->last_name = $ldap_attr['lastname'];
$user->save();
} else {
LOG::debug("User ".Input::get('username')." did not authenticate correctly against LDAP. Local user was not updated.");
}// End LDAP auth
} // End if(!user)
// NO LDAP enabled - just try to login the user normally
}
LOG::debug("Authenticating user against database.");
// Try to log the user in
if (!Auth::attempt(Input::only('username', 'password'), Input::get('remember-me', 0))) {
LOG::debug("Local authentication failed.");
// throw new Cartalyst\Sentry\Users\UserNotFoundException();
return redirect()->back()->withInput()->with('error', trans('auth/message.account_not_found'));
}
// Get the page we were before
$redirect = \Session::get('loginRedirect', 'home');
// Unset the page we were before from the session
\Session::forget('loginRedirect');
// Redirect to the users page
return redirect()->to($redirect)->with('success', trans('auth/message.signin.success'));
// Ooops.. something went wrong
return redirect()->back()->withInput()->withErrors($this->messageBag);
}
/**
* Logout page.
*
* @return Redirect
*/
public function logout()
{
// Log the user out
Auth::logout();
// Redirect to the users page
return redirect()->route('home')->with('success', 'You have successfully logged out!');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'username' => 'required',
'password' => 'required',
]);
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
/**
* This controller handles password resets for the user.
* It uses the built-in Laravel magic of ResetsPasswords, so we
* don't actually do much here.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @version v1.0
*/
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new password controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
}
+532
View File
@@ -0,0 +1,532 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Category as Category;
use App\Models\Company;
use App\Models\Setting;
use Auth;
use DB;
use Input;
use Lang;
use Redirect;
use Str;
use View;
/**
* This class controls all actions related to Categories for
* the Snipe-IT Asset Management application.
*
* @version v1.0
* @author [A. Gianotto] [<snipe@snipe.net>]
*/
class CategoriesController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the categories listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Show the page
return View::make('categories/index');
}
/**
* Returns a form view to create a new category.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::postCreate() method that stores the data
* @since [v1.0]
* @return View
*/
public function getCreate()
{
// Show the page
$category_types= Helper::categoryTypeList();
return View::make('categories/edit')->with('category', new Category)
->with('category_types', $category_types);
}
/**
* Validates and stores the new category data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::getCreate() method that makes the form.
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
// create a new model instance
$category = new Category();
// Update the category data
$category->name = e(Input::get('name'));
$category->category_type = e(Input::get('category_type'));
$category->eula_text = e(Input::get('eula_text'));
$category->use_default_eula = e(Input::get('use_default_eula', '0'));
$category->require_acceptance = e(Input::get('require_acceptance', '0'));
$category->checkin_email = e(Input::get('checkin_email', '0'));
$category->user_id = Auth::user()->id;
if ($category->save()) {
// Redirect to the new category page
return redirect()->to("admin/settings/categories")->with('success', trans('admin/categories/message.create.success'));
} else {
// The given data did not pass validation
return redirect()->back()->withInput()->withErrors($category->getErrors());
}
// Redirect to the category create page
return redirect()->to('admin/settings/categories/create')->with('error', trans('admin/categories/message.create.error'));
}
/**
* Returns a view that makes a form to update a category.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::postEdit() method saves the data
* @param int $categoryId
* @since [v1.0]
* @return View
*/
public function getEdit($categoryId = null)
{
// Check if the category exists
if (is_null($category = Category::find($categoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.does_not_exist'));
}
// Show the page
//$category_options = array('' => 'Top Level') + Category::lists('name', 'id');
$category_options = array('' => 'Top Level') + DB::table('categories')->where('id', '!=', $categoryId)->lists('name', 'id');
$category_types= Helper::categoryTypeList();
return View::make('categories/edit', compact('category'))
->with('category_options', $category_options)
->with('category_types', $category_types);
}
/**
* Validates and stores the updated category data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::getEdit() method that makes the form.
* @param int $categoryId
* @since [v1.0]
* @return Redirect
*/
public function postEdit($categoryId = null)
{
// Check if the blog post exists
if (is_null($category = Category::find($categoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/categories')->with('error', trans('admin/categories/message.does_not_exist'));
}
// Update the category data
$category->name = e(Input::get('name'));
$category->category_type = e(Input::get('category_type'));
$category->eula_text = e(Input::get('eula_text'));
$category->use_default_eula = e(Input::get('use_default_eula', '0'));
$category->require_acceptance = e(Input::get('require_acceptance', '0'));
$category->checkin_email = e(Input::get('checkin_email', '0'));
if ($category->save()) {
// Redirect to the new category page
return redirect()->to("admin/settings/categories")->with('success', trans('admin/categories/message.update.success'));
} // attempt validation
else {
// The given data did not pass validation
return redirect()->back()->withInput()->withErrors($category->getErrors());
}
// Redirect to the category management page
return redirect()->back()->with('error', trans('admin/categories/message.update.error'));
}
/**
* Validates and marks a category as deleted.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param int $categoryId
* @return Redirect
*/
public function getDelete($categoryId)
{
// Check if the category exists
if (is_null($category = Category::find($categoryId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/categories')->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']));
} elseif ($category->accessories()->count() > 0) {
return redirect()->to('admin/settings/categories')->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']));
} elseif ($category->components()->count() > 0) {
return redirect()->to('admin/settings/categories')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component']));
} else {
$category->delete();
// Redirect to the locations management page
return redirect()->to('admin/settings/categories')->with('success', trans('admin/categories/message.delete.success'));
}
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the categories detail view, which is generated in getDataView.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::getDataView() method that generates the JSON response
* @param int $categoryId
* @since [v1.8]
* @return View
*/
public function getView($categoryId = null)
{
$category = Category::find($categoryId);
if (isset($category->id)) {
return View::make('categories/view', compact('category'));
} else {
// Prepare the error message
$error = trans('admin/categories/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('categories')->with('error', $error);
}
}
/**
* Returns a JSON response with the data to populate the bootstrap table on the
* cateory listing page.
*
* @todo Refactor this nastiness. Assets do not behave the same as accessories, etc.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see CategoriesController::getIndex() method that generates the view
* @since [v1.8]
* @return String JSON
*/
public function getDatatable()
{
// Grab all the categories
$categories = Category::with('assets', 'accessories', 'consumables', 'components');
if (Input::has('search')) {
$categories = $categories->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','category_type'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? e(Input::get('sort')) : 'created_at';
$categories = $categories->orderBy($sort, $order);
$catCount = $categories->count();
$categories = $categories->skip($offset)->take($limit)->get();
$rows = array();
foreach ($categories as $category) {
$actions = '<a href="'.route('update/category', $category->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;">';
$actions .='<i class="fa fa-pencil icon-white"></i></a>';
$actions .='<a data-html="false" class="btn delete-asset btn-danger btn-sm';
if ($category->itemCount() > 0) {
$actions .=' disabled';
}
$actions .=' data-toggle="modal" href="'.route('delete/category', $category->id).'" data-content="'.trans('admin/categories/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($category->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a>';
$rows[] = array(
'id' => $category->id,
'name' => (string)link_to('/admin/settings/categories/'.$category->id.'/view', $category->name) ,
'category_type' => ucwords($category->category_type),
'count' => $category->itemCount(),
'acceptance' => ($category->require_acceptance=='1') ? '<i class="fa fa-check"></i>' : '',
//EULA is still not working correctly
'eula' => ($category->getEula()) ? '<i class="fa fa-check"></i>' : '',
'actions' => $actions
);
}
$data = array('total' => $catCount, 'rows' => $rows);
return $data;
}
public function getDataViewAssets($categoryID)
{
$category = Category::with('assets.company')->find($categoryID);
$category_assets = $category->assets();
if (Input::has('search')) {
$category_assets = $category_assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$count = $category_assets->count();
$category_assets = $category_assets->skip($offset)->take($limit)->get();
$rows = array();
foreach ($category_assets as $asset) {
$actions = '';
$inout='';
if ($asset->deleted_at=='') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('clone/hardware', $asset->id).'" class="btn btn-info btn-sm" title="Clone asset"><i class="fa fa-files-o"></i></a> <a href="'.route('update/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> <a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/hardware', $asset->id).'" data-content="'.trans('admin/hardware/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($asset->asset_tag).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
} elseif ($asset->deleted_at!='') {
$actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
}
if ($asset->assetstatus) {
if ($asset->assetstatus->deployable != 0) {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) {
$inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>';
} else {
$inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>';
}
}
}
$rows[] = array(
'id' => $asset->id,
'name' => (string)link_to('/hardware/'.$asset->id.'/view', $asset->showAssetName()),
'model' => $asset->model->name,
'asset_tag' => $asset->asset_tag,
'serial' => $asset->serial,
'assigned_to' => ($asset->assigneduser) ? (string)link_to('/admin/users/'.$asset->assigneduser->id.'/view', $asset->assigneduser->fullName()): '',
'change' => $inout,
'actions' => $actions,
'companyName' => Company::getName($asset),
);
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
public function getDataViewAccessories($categoryID)
{
$category = Category::with('accessories.company')->find($categoryID);
$category_assets = $category->accessories;
if (Input::has('search')) {
$category_assets = $category_assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$count = $category_assets->count();
$rows = array();
foreach ($category_assets as $asset) {
$actions = '';
$inout='';
if ($asset->deleted_at=='') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('update/accessory', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> <a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/accessory', $asset->id).'" data-content="'.trans('admin/hardware/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($asset->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
}
$rows[] = array(
'id' => $asset->id,
'name' => (string)link_to_route('view/accessory', $asset->name, [$asset->id]),
'actions' => $actions,
'companyName' => Company::getName($asset),
);
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
public function getDataViewConsumables($categoryID)
{
$category = Category::with('accessories.company')->find($categoryID);
$category_assets = $category->consumables;
if (Input::has('search')) {
$category_assets = $category_assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$count = $category_assets->count();
$rows = array();
foreach ($category_assets as $asset) {
$actions = '';
$inout='';
if ($asset->deleted_at=='') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('update/consumable', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> <a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/consumable', $asset->id).'" data-content="'.trans('admin/hardware/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($asset->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
}
$rows[] = array(
'id' => $asset->id,
'name' => (string) link_to_route('view/consumable', $asset->name, [$asset->id]),
'actions' => $actions,
'companyName' => Company::getName($asset),
);
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
public function getDataViewComponent($categoryID)
{
$category = Category::with('accessories.company')->find($categoryID);
$category_assets = $category->components;
if (Input::has('search')) {
$category_assets = $category_assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$count = $category_assets->count();
$rows = array();
foreach ($category_assets as $asset) {
$actions = '';
$inout='';
if ($asset->deleted_at=='') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('update/component', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> <a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/component', $asset->id).'" data-content="'.trans('admin/hardware/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($asset->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
}
$rows[] = array(
'id' => $asset->id,
'name' => (string)link_to_route('view/accessory', $asset->name, [$asset->id]),
'actions' => $actions,
'companyName' => Company::getName($asset),
);
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
}
@@ -0,0 +1,145 @@
<?php
namespace App\Http\Controllers;
use App\Models\Company;
use Input;
use Lang;
use Redirect;
use View;
/**
* This controller handles all actions related to Companies for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
final class CompaniesController extends Controller
{
/**
* Returns view to display listing of companies.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @return View
*/
public function getIndex()
{
return View::make('companies/index')->with('companies', Company::all());
}
/**
* Returns view to create a new company.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @return View
*/
public function getCreate()
{
return View::make('companies/edit')->with('company', new Company);
}
/**
* Save data from new company form.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
public function postCreate()
{
$company = new Company;
$company->name = e(Input::get('name'));
if ($company->save()) {
return redirect()->to('admin/settings/companies')
->with('success', trans('admin/companies/message.create.success'));
} else {
return redirect()->back()->withInput()->withErrors($company->getErrors());
}
}
/**
* Return form to edit existing company.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return View
*/
public function getEdit($companyId)
{
if (is_null($company = Company::find($companyId))) {
return redirect()->to('admin/settings/companies')
->with('error', trans('admin/companies/message.does_not_exist'));
} else {
return View::make('companies/edit')->with('company', $company);
}
}
/**
* Save data from edit company form.
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return Redirect
*/
public function postEdit($companyId)
{
if (is_null($company = Company::find($companyId))) {
return redirect()->to('admin/settings/companies')->with('error', trans('admin/companies/message.does_not_exist'));
} else {
$company->name = e(Input::get('name'));
if ($company->save()) {
return redirect()->to('admin/settings/companies')
->with('success', trans('admin/companies/message.update.success'));
} else {
return redirect()->to("admin/settings/companies/$companyId/edit")
->with('error', trans('admin/companies/message.update.error'));
}
}
}
/**
* Delete company
*
* @author [Abdullah Alansari] [<ahimta@gmail.com>]
* @since [v1.8]
* @param int $companyId
* @return Redirect
*/
public function postDelete($companyId)
{
if (is_null($company = Company::find($companyId))) {
return redirect()->to('admin/settings/companies')
->with('error', trans('admin/companies/message.not_found'));
} else {
try {
$company->delete();
return redirect()->to('admin/settings/companies')
->with('success', trans('admin/companies/message.delete.success'));
} catch (\Illuminate\Database\QueryException $exception) {
/*
* NOTE: This happens when there's a foreign key constraint violation
* For example when rows in other tables are referencing this company
*/
if ($exception->getCode() == 23000) {
return redirect()->to('admin/settings/companies')
->with('error', trans('admin/companies/message.assoc_users'));
} else {
throw $exception;
}
}
}
}
}
@@ -0,0 +1,516 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use App\Models\Asset;
use Auth;
use Config;
use DB;
use Input;
use Lang;
use Mail;
use Redirect;
use Slack;
use Str;
use View;
use Validator;
use Illuminate\Http\Request;
/**
* This class controls all actions related to Components for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ComponentsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the components listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getDatatable() method that generates the JSON response
* @since [v3.0]
* @return View
*/
public function getIndex()
{
return View::make('components/index');
}
/**
* Returns a form to create a new component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::postCreate() method that stores the data
* @since [v3.0]
* @return View
*/
public function getCreate()
{
// Show the page
$category_list = Helper::categoryList('component');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
return View::make('components/edit')
->with('component', new Component)
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list);
}
/**
* Validate and store data for new component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getCreate() method that generates the view
* @since [v3.0]
* @return Redirect
*/
public function postCreate()
{
// create a new model instance
$component = new Component();
// Update the component data
$component->name = e(Input::get('name'));
$component->category_id = e(Input::get('category_id'));
$component->location_id = e(Input::get('location_id'));
$component->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$component->order_number = e(Input::get('order_number'));
$component->min_amt = e(Input::get('min_amt'));
if (e(Input::get('purchase_date')) == '') {
$component->purchase_date = null;
} else {
$component->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$component->purchase_cost = null;
} else {
$component->purchase_cost = e(Input::get('purchase_cost'));
}
$component->total_qty = e(Input::get('total_qty'));
$component->user_id = Auth::user()->id;
// Was the component created?
if ($component->save()) {
// Redirect to the new component page
return redirect()->to("admin/components")->with('success', trans('admin/components/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($component->getErrors());
}
/**
* Return a view to edit a component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::postEdit() method that stores the data.
* @since [v3.0]
* @param int $componentId
* @return View
*/
public function getEdit($componentId = null)
{
// Check if the component exists
if (is_null($component = Component::find($componentId))) {
// Redirect to the blogs management page
return redirect()->to('admin/components')->with('error', trans('admin/components/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
}
$category_list = Helper::categoryList('component');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
return View::make('components/edit', compact('component'))
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list);
}
/**
* Return a view to edit a component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getEdit() method presents the form.
* @param int $componentId
* @since [v3.0]
* @return Redirect
*/
public function postEdit($componentId = null)
{
// Check if the blog post exists
if (is_null($component = Component::find($componentId))) {
// Redirect to the blogs management page
return redirect()->to('admin/components')->with('error', trans('admin/components/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
}
// Update the component data
$component->name = e(Input::get('name'));
$component->category_id = e(Input::get('category_id'));
$component->location_id = e(Input::get('location_id'));
$component->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$component->order_number = e(Input::get('order_number'));
$component->min_amt = e(Input::get('min_amt'));
if (e(Input::get('purchase_date')) == '') {
$component->purchase_date = null;
} else {
$component->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$component->purchase_cost = null;
} else {
$component->purchase_cost = e(Input::get('purchase_cost'));
}
$component->total_qty = e(Input::get('total_qty'));
// Was the component created?
if ($component->save()) {
// Redirect to the new component page
return redirect()->to("admin/components")->with('success', trans('admin/components/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($component->getErrors());
}
/**
* Delete a component.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param int $componentId
* @return Redirect
*/
public function getDelete($componentId)
{
// Check if the blog post exists
if (is_null($component = Component::find($componentId))) {
// Redirect to the blogs management page
return redirect()->to('admin/components')->with('error', trans('admin/components/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
}
$component->delete();
// Redirect to the locations management page
return redirect()->to('admin/components')->with('success', trans('admin/components/message.delete.success'));
}
public function postBulk($componentId = null)
{
echo 'Stubbed - not yet complete';
}
public function postBulkSave($componentId = null)
{
echo 'Stubbed - not yet complete';
}
/**
* Return a view to display component information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getDataView() method that generates the JSON response
* @since [v3.0]
* @param int $componentId
* @return View
*/
public function getView($componentId = null)
{
$component = Component::find($componentId);
if (isset($component->id)) {
if (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
} else {
return View::make('components/view', compact('component'));
}
} else {
// Prepare the error message
$error = trans('admin/components/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('components')->with('error', $error);
}
}
/**
* Returns a view that allows the checkout of a component to an asset.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::postCheckout() method that stores the data.
* @since [v3.0]
* @param int $componentId
* @return View
*/
public function getCheckout($componentId)
{
// Check if the component exists
if (is_null($component = Component::find($componentId))) {
// Redirect to the component management page with error
return redirect()->to('components')->with('error', trans('admin/components/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
}
// Get the dropdown of assets and then pass it to the checkout view
$assets_list = Helper::detailedAssetList();
return View::make('components/checkout', compact('component'))->with('assets_list', $assets_list);
}
/**
* Validate and store checkout data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ComponentsController::getCheckout() method that returns the form.
* @since [v3.0]
* @param int $componentId
* @return Redirect
*/
public function postCheckout(Request $request, $componentId)
{
// Check if the component exists
if (is_null($component = Component::find($componentId))) {
// Redirect to the component management page with error
return redirect()->to('components')->with('error', trans('admin/components/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($component)) {
return redirect()->to('admin/components')->with('error', trans('general.insufficient_permissions'));
}
$max_to_checkout = $component->numRemaining();
$validator = Validator::make($request->all(),[
"asset_id" => "required",
"assigned_qty" => "required|numeric|between:1,$max_to_checkout"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$admin_user = Auth::user();
$asset_id = e(Input::get('asset_id'));
// Check if the user exists
if (is_null($asset = Asset::find($asset_id))) {
// Redirect to the component management page with error
return redirect()->to('admin/components')->with('error', trans('admin/components/message.asset_does_not_exist'));
}
// Update the component data
$component->asset_id = $asset_id;
$component->assets()->attach($component->id, array(
'component_id' => $component->id,
'user_id' => $admin_user->id,
'created_at' => date('Y-m-d h:i:s'),
'assigned_qty' => e(Input::get('assigned_qty')),
'asset_id' => $asset_id));
$logaction = new Actionlog();
$logaction->component_id = $component->id;
$logaction->asset_id = $asset_id;
$logaction->asset_type = 'component';
$logaction->location_id = $asset->location_id;
$logaction->user_id = Auth::user()->id;
$logaction->note = e(Input::get('note'));
$settings = Setting::getSettings();
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'Checked Out:',
'value' => strtoupper($logaction->asset_type).' <'.config('app.url').'/admin/components/'.$component->id.'/view'.'|'.$component->name.'> checked out to <'.config('app.url').'/hardware/'.$asset->id.'/view|'.$asset->name.'> by <'.config('app.url').'/admin/users/'.$admin_user->id.'/view'.'|'.$admin_user->fullName().'>.'
],
[
'title' => 'Note:',
'value' => e($logaction->note)
],
]
])->send('Component Checked Out');
} catch (Exception $e) {
}
}
$log = $logaction->logaction('checkout');
// Redirect to the new component page
return redirect()->to("admin/components")->with('success', trans('admin/components/message.checkout.success'));
}
/**
* Generates the JSON response for accessories listing view.
*
* For debugging, see at /api/accessories/list
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return string JSON
**/
public function getDatatable()
{
$components = Component::select('components.*')->whereNull('components.deleted_at')
->with('company', 'location', 'category');
if (Input::has('search')) {
$components = $components->TextSearch(Input::get('search'));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','min_amt','order_number','purchase_date','purchase_cost','companyName','category','total_qty'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
switch ($sort) {
case 'category':
$components = $components->OrderCategory($order);
break;
case 'location':
$components = $components->OrderLocation($order);
break;
case 'companyName':
$components = $components->OrderCompany($order);
break;
default:
$components = $components->orderBy($sort, $order);
break;
}
$consumCount = $components->count();
$components = $components->skip($offset)->take($limit)->get();
$rows = array();
foreach ($components as $component) {
$actions = '<nobr><a href="'.route('checkout/component', $component->id).'" style="margin-right:5px;" class="btn btn-info btn-sm '.(($component->numRemaining() > 0 ) ? '' : ' disabled').'" '.(($component->numRemaining() > 0 ) ? '' : ' disabled').'>'.trans('general.checkout').'</a><a href="'.route('update/component', $component->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/component', $component->id).'" data-content="'.trans('admin/components/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($component->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></nobr>';
$company = $component->company;
$rows[] = array(
'checkbox' =>'<div class="text-center"><input type="checkbox" name="component['.$component->id.']" class="one_required"></div>',
'id' => $component->id,
'name' => (string)link_to('admin/components/'.$component->id.'/view', e($component->name)),
'location' => ($component->location) ? e($component->location->name) : '',
'total_qty' => e($component->total_qty),
'min_amt' => e($component->min_amt),
'category' => ($component->category) ? e($component->category->name) : 'Missing category',
'order_number' => e($component->order_number),
'purchase_date' => e($component->purchase_date),
'purchase_cost' => ($component->purchase_cost!='') ? number_format($component->purchase_cost, 2): '' ,
'numRemaining' => $component->numRemaining(),
'actions' => $actions,
'companyName' => is_null($company) ? '' : e($company->name),
);
}
$data = array('total' => $consumCount, 'rows' => $rows);
return $data;
}
/**
* 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)
{
//$component = Component::find($componentID);
$component = Component::with('assets')->find($componentId);
if (!Company::isCurrentUserHasAccess($component)) {
return ['total' => 0, 'rows' => []];
}
$rows = array();
foreach ($component->assets as $component_assignment) {
$rows[] = array(
'name' => (string)link_to('/hardware/'.$component_assignment->id.'/view', e($component_assignment->name)),
'qty' => e($component_assignment->pivot->assigned_qty),
'created_at' => ($component_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $component_assignment->created_at->format('Y-m-d H:i:s'),
);
}
$componentCount = $component->assets->count();
$data = array('total' => $componentCount, 'rows' => $rows);
return $data;
}
}
@@ -0,0 +1,517 @@
<?php
namespace App\Http\Controllers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\Setting;
use App\Models\User;
use Auth;
use Config;
use DB;
use Input;
use Lang;
use Mail;
use Redirect;
use Slack;
use Str;
use View;
/**
* This controller handles all actions related to Consumables for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ConsumablesController extends Controller
{
/**
* Return a view to display component information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
return View::make('consumables/index');
}
/**
* Return a view to display the form view to create a new consumable
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::postCreate() method that stores the form data
* @since [v1.0]
* @return View
*/
public function getCreate()
{
// Show the page
$category_list = Helper::categoryList('consumable');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
$manufacturer_list = Helper::manufacturerList();
return View::make('consumables/edit')
->with('consumable', new Consumable)
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list)
->with('manufacturer_list', $manufacturer_list);
}
/**
* Validate and store new consumable data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getCreate() method that returns the form view
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
$consumable = new Consumable();
$consumable->name = e(Input::get('name'));
$consumable->category_id = e(Input::get('category_id'));
$consumable->location_id = e(Input::get('location_id'));
$consumable->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$consumable->order_number = e(Input::get('order_number'));
$consumable->min_amt = e(Input::get('min_amt'));
$consumable->manufacturer_id = e(Input::get('manufacturer_id'));
$consumable->model_no = e(Input::get('model_no'));
$consumable->item_no = e(Input::get('item_no'));
if (e(Input::get('purchase_date')) == '') {
$consumable->purchase_date = null;
} else {
$consumable->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$consumable->purchase_cost = null;
} else {
$consumable->purchase_cost = e(Input::get('purchase_cost'));
}
$consumable->qty = e(Input::get('qty'));
$consumable->user_id = Auth::user()->id;
// Was the consumable created?
if ($consumable->save()) {
// Redirect to the new consumable page
return redirect()->to("admin/consumables")->with('success', trans('admin/consumables/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
}
/**
* Returns a form view to edit a consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $consumableId
* @see ConsumablesController::postEdit() method that stores the form data.
* @since [v1.0]
* @return View
*/
public function getEdit($consumableId = null)
{
// Check if the consumable exists
if (is_null($consumable = Consumable::find($consumableId))) {
// Redirect to the blogs management page
return redirect()->to('admin/consumables')->with('error', trans('admin/consumables/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
}
$category_list = Helper::categoryList('consumable');
$company_list = Helper::companyList();
$location_list = Helper::locationsList();
$manufacturer_list = Helper::manufacturerList();
return View::make('consumables/edit', compact('consumable'))
->with('category_list', $category_list)
->with('company_list', $company_list)
->with('location_list', $location_list)
->with('manufacturer_list', $manufacturer_list);
}
/**
* Returns a form view to edit a consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $consumableId
* @see ConsumablesController::getEdit() method that stores the form data.
* @since [v1.0]
* @return Redirect
*/
public function postEdit($consumableId = null)
{
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->to('admin/consumables')->with('error', trans('admin/consumables/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
}
$consumable->name = e(Input::get('name'));
$consumable->category_id = e(Input::get('category_id'));
$consumable->location_id = e(Input::get('location_id'));
$consumable->company_id = Company::getIdForCurrentUser(Input::get('company_id'));
$consumable->order_number = e(Input::get('order_number'));
$consumable->min_amt = e(Input::get('min_amt'));
$consumable->manufacturer_id = e(Input::get('manufacturer_id'));
$consumable->model_no = e(Input::get('model_no'));
$consumable->item_no = e(Input::get('item_no'));
if (e(Input::get('purchase_date')) == '') {
$consumable->purchase_date = null;
} else {
$consumable->purchase_date = e(Input::get('purchase_date'));
}
if (e(Input::get('purchase_cost')) == '0.00') {
$consumable->purchase_cost = null;
} else {
$consumable->purchase_cost = e(Input::get('purchase_cost'));
}
$consumable->qty = e(Input::get('qty'));
if ($consumable->save()) {
return redirect()->to("admin/consumables")->with('success', trans('admin/consumables/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($consumable->getErrors());
}
/**
* Delete a consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $consumableId
* @since [v1.0]
* @return Redirect
*/
public function getDelete($consumableId)
{
// Check if the blog post exists
if (is_null($consumable = Consumable::find($consumableId))) {
// Redirect to the blogs management page
return redirect()->to('admin/consumables')->with('error', trans('admin/consumables/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
}
$consumable->delete();
// Redirect to the locations management page
return redirect()->to('admin/consumables')->with('success', trans('admin/consumables/message.delete.success'));
}
/**
* Return a view to display component information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getDataView() method that generates the JSON response
* @since [v1.0]
* @param int $consumableId
* @return View
*/
public function getView($consumableId = null)
{
$consumable = Consumable::find($consumableId);
if (isset($consumable->id)) {
if (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
} else {
return View::make('consumables/view', compact('consumable'));
}
} else {
// Prepare the error message
$error = trans('admin/consumables/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('consumables')->with('error', $error);
}
}
/**
* Return a view to checkout a consumable to a user.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::postCheckout() method that stores the data.
* @since [v1.0]
* @param int $consumableId
* @return View
*/
public function getCheckout($consumableId)
{
// Check if the consumable exists
if (is_null($consumable = Consumable::find($consumableId))) {
// Redirect to the consumable management page with error
return redirect()->to('consumables')->with('error', trans('admin/consumables/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
}
// Get the dropdown of users and then pass it to the checkout view
$users_list = Helper::usersList();
return View::make('consumables/checkout', compact('consumable'))->with('users_list', $users_list);
}
/**
* Saves the checkout information
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getCheckout() method that returns the form.
* @since [v1.0]
* @param int $consumableId
* @return Redirect
*/
public function postCheckout($consumableId)
{
// Check if the consumable exists
if (is_null($consumable = Consumable::find($consumableId))) {
// Redirect to the consumable management page with error
return redirect()->to('consumables')->with('error', trans('admin/consumables/message.not_found'));
} elseif (!Company::isCurrentUserHasAccess($consumable)) {
return redirect()->to('admin/consumables')->with('error', trans('general.insufficient_permissions'));
}
$admin_user = Auth::user();
$assigned_to = e(Input::get('assigned_to'));
// Check if the user exists
if (is_null($user = User::find($assigned_to))) {
// Redirect to the consumable management page with error
return redirect()->to('admin/consumables')->with('error', trans('admin/consumables/message.user_does_not_exist'));
}
// Update the consumable data
$consumable->assigned_to = e(Input::get('assigned_to'));
$consumable->users()->attach($consumable->id, array(
'consumable_id' => $consumable->id,
'user_id' => $admin_user->id,
'assigned_to' => e(Input::get('assigned_to'))));
$logaction = new Actionlog();
$logaction->consumable_id = $consumable->id;
$logaction->checkedout_to = $consumable->assigned_to;
$logaction->asset_type = 'consumable';
$logaction->asset_id = 0;
$logaction->location_id = $user->location_id;
$logaction->user_id = Auth::user()->id;
$logaction->note = e(Input::get('note'));
$settings = Setting::getSettings();
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'Checked Out:',
'value' => strtoupper($logaction->asset_type).' <'.config('app.url').'/admin/consumables/'.$consumable->id.'/view'.'|'.$consumable->name.'> checked out to <'.config('app.url').'/admin/users/'.$user->id.'/view|'.$user->fullName().'> by <'.config('app.url').'/admin/users/'.$admin_user->id.'/view'.'|'.$admin_user->fullName().'>.'
],
[
'title' => 'Note:',
'value' => e($logaction->note)
],
]
])->send('Consumable Checked Out');
} catch (Exception $e) {
}
}
$log = $logaction->logaction('checkout');
$consumable_user = DB::table('consumables_users')->where('assigned_to', '=', $consumable->assigned_to)->where('consumable_id', '=', $consumable->id)->first();
$data['log_id'] = $logaction->id;
$data['eula'] = $consumable->getEula();
$data['first_name'] = $user->first_name;
$data['item_name'] = $consumable->name;
$data['checkout_date'] = $logaction->created_at;
$data['note'] = $logaction->note;
$data['require_acceptance'] = $consumable->requireAcceptance();
if (($consumable->requireAcceptance()=='1') || ($consumable->getEula())) {
Mail::send('emails.accept-asset', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->subject('Confirm consumable delivery');
});
}
// Redirect to the new consumable page
return redirect()->to("admin/consumables")->with('success', trans('admin/consumables/message.checkout.success'));
}
/**
* Returns the JSON response containing the the consumables data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getIndex() method that returns the view that consumes the JSON.
* @since [v1.0]
* @param int $consumableId
* @return View
*/
public function getDatatable()
{
$consumables = Consumable::select('consumables.*')->whereNull('consumables.deleted_at')
->with('company', 'location', 'category', 'users');
if (Input::has('search')) {
$consumables = $consumables->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','order_number','min_amt','purchase_date','purchase_cost','companyName','category','model_no', 'item_no', 'manufacturer'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
switch ($sort) {
case 'category':
$consumables = $consumables->OrderCategory($order);
break;
case 'location':
$consumables = $consumables->OrderLocation($order);
break;
case 'manufacturer':
$consumables = $consumables->OrderManufacturer($order);
break;
case 'companyName':
$consumables = $consumables->OrderCompany($order);
break;
default:
$consumables = $consumables->orderBy($sort, $order);
break;
}
$consumCount = $consumables->count();
$consumables = $consumables->skip($offset)->take($limit)->get();
$rows = array();
foreach ($consumables as $consumable) {
$actions = '<nobr><a href="'.route('checkout/consumable', $consumable->id).'" style="margin-right:5px;" class="btn btn-info btn-sm" '.(($consumable->numRemaining() > 0 ) ? '' : ' disabled').'>'.trans('general.checkout').'</a><a href="'.route('update/consumable', $consumable->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/consumable', $consumable->id).'" data-content="'.trans('admin/consumables/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($consumable->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></nobr>';
$company = $consumable->company;
$rows[] = array(
'id' => $consumable->id,
'name' => (string)link_to('admin/consumables/'.$consumable->id.'/view', e($consumable->name)),
'location' => ($consumable->location) ? e($consumable->location->name) : '',
'min_amt' => e($consumable->min_amt),
'qty' => e($consumable->qty),
'manufacturer' => ($consumable->manufacturer) ? e($consumable->manufacturer->name) : '',
'model_no' => e($consumable->model_no),
'item_no' => e($consumable->item_no),
'category' => ($consumable->category) ? e($consumable->category->name) : 'Missing category',
'order_number' => e($consumable->order_number),
'purchase_date' => e($consumable->purchase_date),
'purchase_cost' => ($consumable->purchase_cost!='') ? number_format($consumable->purchase_cost, 2): '' ,
'numRemaining' => $consumable->numRemaining(),
'actions' => $actions,
'companyName' => is_null($company) ? '' : e($company->name),
);
}
$data = array('total' => $consumCount, 'rows' => $rows);
return $data;
}
/**
* Returns a JSON response containing details on the users associated with this consumable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ConsumablesController::getView() method that returns the form.
* @since [v1.0]
* @param int $consumableId
* @return View
*/
public function getDataView($consumableId)
{
//$consumable = Consumable::find($consumableID);
$consumable = Consumable::with(array('consumableAssigments'=>
function ($query) {
$query->orderBy('created_at', 'DESC');
},
'consumableAssigments.admin'=> function ($query) {
},
'consumableAssigments.user'=> function ($query) {
},
))->find($consumableId);
// $consumable->load('consumableAssigments.admin','consumableAssigments.user');
if (!Company::isCurrentUserHasAccess($consumable)) {
return ['total' => 0, 'rows' => []];
}
$rows = array();
foreach ($consumable->consumableAssigments as $consumable_assignment) {
$rows[] = array(
'name' => (string)link_to('/admin/users/'.$consumable_assignment->user->id.'/view', e($consumable_assignment->user->fullName())),
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
'admin' => ($consumable_assignment->admin) ? e($consumable_assignment->admin->fullName()) : '',
);
}
$consumableCount = $consumable->users->count();
$data = array('total' => $consumableCount, 'rows' => $rows);
return $data;
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
/*! \mainpage Snipe-IT Code Documentation
*
* \section intro_sec Introduction
*
* This documentation is designed to allow developers to easily understand
* the backend code of Snipe-IT. Familiarity with the PHP language is assumed,
* and experience with the Laravel framework (version 5.2) will be very helpful.
*
* **THIS DOCUMENTATION DOES NOT COVER INSTALLATION.** If you're here and you're not a
* developer, you're probably in the wrong place. Please see the
* [Installation documentation](http://docs.snipeitapp.com) for
* information on how to install Snipe-IT.
*
* To learn how to set up a development environment and get started developing for Snipe-IT,
* please see the [contributing documentation](http://docs.snipeitapp.com/contributing.html).
*
* Only the Snipe-IT specific controllers, models, helpers, service providers,
* etc have been included in this documentation (excluding vendors, Laravel core, etc)
* for simplicity.
*/
namespace App\Http\Controllers;
use Auth;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
abstract class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct()
{
view()->share('signedIn', Auth::check());
view()->share('user', Auth::user());
}
}
@@ -0,0 +1,277 @@
<?php
namespace App\Http\Controllers;
use View;
use App\Models\CustomFieldset;
use App\Models\CustomField;
use Input;
use Validator;
use Redirect;
use App\Models\AssetModel;
use Lang;
use Auth;
/**
* This controller handles all actions related to Custom Asset Fields for
* the Snipe-IT Asset Management application.
*
* @todo Improve documentation here.
* @todo Check for raw DB queries and try to convert them to query builder statements
* @version v2.0
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
*/
class CustomFieldsController extends Controller
{
/**
* Returns a view with a listing of custom fields.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
public function index()
{
//
$fieldsets=CustomFieldset::with("fields", "models")->get();
//$fieldsets=CustomFieldset::all();
$fields=CustomField::with("fieldset")->get();
//$fields=CustomField::all();
return View::make("custom_fields.index")->with("custom_fieldsets", $fieldsets)->with("custom_fields", $fields);
}
/**
* Returns a view with a form for creating a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
public function create()
{
//
return View::make("custom_fields.create");
}
/**
* Validates and stores a new custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
public function store()
{
//
$cfset=new CustomFieldset(["name" => Input::get("name"),"user_id" => Auth::user()->id]);
$validator=Validator::make(Input::all(), $cfset->rules);
if ($validator->passes()) {
$cfset->save();
return redirect()->route("admin.custom_fields.show", [$cfset->id])->with('success', trans('admin/custom_fields/message.fieldset.create.success'));
} else {
return redirect()->back()->withInput()->withErrors($validator);
}
}
/**
* Associate the custom field with a custom fieldset.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
public function associate($id)
{
$set = CustomFieldset::find($id);
foreach ($set->fields as $field) {
if ($field->id == Input::get('field_id')) {
return redirect()->route("admin.custom_fields.show", [$id])->withInput()->withErrors(['field_id' => trans('admin/custom_fields/message.field.already_added')]);
}
}
$results=$set->fields()->attach(Input::get('field_id'), ["required" => (Input::get('required') == "on"),"order" => Input::get('order')]);
return redirect()->route("admin.custom_fields.show", [$id])->with("success", trans('admin/custom_fields/message.field.create.assoc_success'));
}
/**
* Returns a view with a form to create a new custom field.
*
* @see CustomFieldsController::storeField()
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return View
*/
public function createField()
{
return View::make("custom_fields.create_field");
}
/**
* Validates and stores a new custom field.
*
* @see CustomFieldsController::createField()
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
public function storeField()
{
$field=new CustomField(["name" => Input::get("name"),"element" => Input::get("element"),"user_id" => Auth::user()->id]);
if (!in_array(Input::get('format'), array_keys(CustomField::$PredefinedFormats))) {
$field->format=Input::get("custom_format");
} else {
$field->format=Input::get('format');
}
$validator=Validator::make(Input::all(), $field->rules);
if ($validator->passes()) {
$results=$field->save();
//return "postCreateField: $results";
if ($results) {
return redirect()->route("admin.custom_fields.index")->with("success", trans('admin/custom_fields/message.field.create.success'));
} else {
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.field.create.error'));
}
} else {
return redirect()->back()->withInput()->withErrors($validator);
}
}
/**
* Delete a custom field.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @since [v1.8]
* @return Redirect
*/
public function deleteField($field_id)
{
$field=CustomField::find($field_id);
if ($field->fieldset->count()>0) {
return redirect()->back()->withErrors(['message' => "Field is in-use"]);
} else {
$field->delete();
return redirect()->route("admin.custom_fields.index")->with("success", trans('admin/custom_fields/message.field.delete.success'));
}
}
/**
* Validates and stores a new custom field.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return View
*/
public function show($id)
{
//$id=$parameters[0];
$cfset=CustomFieldset::find($id);
//print_r($parameters);
//
$custom_fields_list=["" => "Add New Field to Fieldset"] + CustomField::lists("name", "id")->toArray();
// print_r($custom_fields_list);
$maxid=0;
foreach ($cfset->fields as $field) {
// print "Looking for: ".$field->id;
if ($field->pivot->order > $maxid) {
$maxid=$field->pivot->order;
}
if (isset($custom_fields_list[$field->id])) {
// print "Found ".$field->id.", so removing it.<br>";
unset($custom_fields_list[$field->id]);
}
}
return View::make("custom_fields.show")->with("custom_fieldset", $cfset)->with("maxid", $maxid+1)->with("custom_fields_list", $custom_fields_list);
}
/**
* What the actual fuck, Brady?
*
* @todo Uhh, build this?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return Fuckall
*/
public function edit($id)
{
//
}
/**
* GET IN THE SEA BRADY.
*
* @todo Uhh, build this too?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return Fuckall
*/
public function update($id)
{
//
}
/**
* Validates a custom fieldset and then deletes if it has no models associated.
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v1.8]
* @return View
*/
public function destroy($id)
{
//
$fieldset=CustomFieldset::find($id);
$models = AssetModel::where("fieldset_id", "=", $id);
if ($models->count()==0) {
$fieldset->delete();
return redirect()->route("admin.custom_fields.index")->with("success", trans('admin/custom_fields/message.fieldset.delete.success'));
} else {
return redirect()->route("admin.custom_fields.index")->with("error", trans('admin/custom_fields/message.fieldset.delete.in_use')); //->with("models",$models);
}
}
/**
* Reorder the custom fields within a fieldset
*
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v3.0]
* @return Array
*/
public function postReorder($id)
{
$fieldset=CustomFieldset::find($id);
$fields = array();
$items = Input::get('item');
foreach ($fieldset->fields as $field) {
$value = array_shift($items);
$fields[$field->id] = ['required' => $field->pivot->required, 'order' => $value];
}
return $fieldset->fields()->sync($fields);
}
}
+91
View File
@@ -0,0 +1,91 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\AdminController;
use App\Models\Actionlog;
use View;
use Auth;
use Redirect;
use App\Models\Asset;
use App\Models\Company;
/**
* This controller handles all actions related to the Admin Dashboard
* for the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class DashboardController extends Controller
{
/**
* Check authorization and display admin dashboard, otherwise display
* the user's checked-out assets.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Show the page
if (Auth::user()->hasAccess('admin')) {
$recent_activity = Actionlog::orderBy('created_at', 'DESC')
->with('accessorylog', 'consumablelog', 'licenselog', 'assetlog', 'adminlog', 'userlog', 'componentlog')
->take(30)
->get();
$asset_stats['total'] = Asset::Hardware()->count();
$asset_stats['rtd']['total'] = Asset::Hardware()->RTD()->count();
if ($asset_stats['rtd']['total'] > 0) {
$asset_stats['rtd']['percent'] = round(($asset_stats['rtd']['total']/$asset_stats['total']) * 100);
} else {
$asset_stats['rtd']['percent'] = 0;
}
$asset_stats['pending']['total'] = Asset::Hardware()->Pending()->count();
if ($asset_stats['pending']['total'] > 0) {
$asset_stats['pending']['percent'] = round(($asset_stats['pending']['total']/$asset_stats['total']) * 100);
} else {
$asset_stats['pending']['percent'] = 0;
}
$asset_stats['deployed']['total'] = Asset::Hardware()->Deployed()->count();
if ($asset_stats['deployed']['total'] > 0) {
$asset_stats['deployed']['percent'] = round(($asset_stats['deployed']['total']/$asset_stats['total']) * 100);
} else {
$asset_stats['deployed']['percent'] = 0;
}
$asset_stats['undeployable']['total'] = Asset::Hardware()->Undeployable()->count();
if ($asset_stats['undeployable']['total'] > 0) {
$asset_stats['undeployable']['percent'] = round(($asset_stats['undeployable']['total']/$asset_stats['total']) * 100);
} else {
$asset_stats['undeployable']['percent'] = 0;
}
$asset_stats['archived']['total'] = Asset::Hardware()->Archived()->count();
if ($asset_stats['archived']['total'] > 0) {
$asset_stats['archived']['percent'] = round(($asset_stats['archived']['total']/$asset_stats['total']) * 100);
} else {
$asset_stats['archived']['percent'] = 0;
}
return View::make('dashboard')->with('asset_stats', $asset_stats)->with('recent_activity', $recent_activity);
} else {
// Redirect to the profile page
return redirect()->route('view-assets');
}
}
}
+226
View File
@@ -0,0 +1,226 @@
<?php
namespace App\Http\Controllers;
use Input;
use Lang;
use App\Models\Depreciation;
use Redirect;
use App\Models\Setting;
use DB;
use Str;
use View;
use Auth;
/**
* This controller handles all actions related to Depreciations for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class DepreciationsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the depreciation listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Show the page
return View::make('depreciations/index', compact('depreciations'));
}
/**
* Returns a view that displays a form to create a new depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postCreate()
* @since [v1.0]
* @return View
*/
public function getCreate()
{
// Show the page
return View::make('depreciations/edit')->with('depreciation', new Depreciation);
}
/**
* Validates and stores the new depreciation data.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postCreate()
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
// get the POST data
$new = Input::all();
// create a new instance
$depreciation = new Depreciation();
// Depreciation data
$depreciation->name = e(Input::get('name'));
$depreciation->months = e(Input::get('months'));
$depreciation->user_id = Auth::user()->id;
// Was the asset created?
if ($depreciation->save()) {
// Redirect to the new depreciation page
return redirect()->to("admin/settings/depreciations")->with('success', trans('admin/depreciations/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($depreciation->getErrors());
}
/**
* Returns a view that displays a form to update a depreciation.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::postEdit()
* @param int $depreciationId
* @since [v1.0]
* @return View
*/
public function getEdit($depreciationId = null)
{
// Check if the depreciation exists
if (is_null($depreciation = Depreciation::find($depreciationId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/depreciations')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
return View::make('depreciations/edit', compact('depreciation'));
}
/**
* Validates and stores the updated depreciation data.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see DepreciationsController::getEdit()
* @param int $depreciationId
* @since [v1.0]
* @return Redirect
*/
public function postEdit($depreciationId = null)
{
// Check if the depreciation exists
if (is_null($depreciation = Depreciation::find($depreciationId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/depreciations')->with('error', trans('admin/depreciations/message.does_not_exist'));
}
// Depreciation data
$depreciation->name = e(Input::get('name'));
$depreciation->months = e(Input::get('months'));
// Was the asset created?
if ($depreciation->save()) {
// Redirect to the depreciation page
return redirect()->to("admin/settings/depreciations/")->with('success', trans('admin/depreciations/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($depreciation->getErrors());
}
/**
* Validates and deletes a selected depreciation.
*
* This is a hard-delete. We do not currently soft-delete depreciations.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @since [v1.0]
* @return Redirect
*/
public function getDelete($depreciationId)
{
// Check if the depreciation exists
if (is_null($depreciation = Depreciation::find($depreciationId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/depreciations')->with('error', trans('admin/depreciations/message.not_found'));
}
if ($depreciation->has_models() > 0) {
// Redirect to the asset management page
return redirect()->to('admin/settings/depreciations')->with('error', trans('admin/depreciations/message.assoc_users'));
} else {
$depreciation->delete();
// Redirect to the depreciations management page
return redirect()->to('admin/settings/depreciations')->with('success', trans('admin/depreciations/message.delete.success'));
}
}
/**
* Generates the JSON used to display the depreciation listing.
*
* @see DepreciationsController::getIndex()
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param string $status
* @since [v1.2]
* @return String JSON
*/
public function getDatatable()
{
$depreciations = Depreciation::select(array('id','name','months'));
if (Input::has('search')) {
$depreciations = $depreciations->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','months'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$depreciations->orderBy($sort, $order);
$depreciationsCount = $depreciations->count();
$depreciations = $depreciations->skip($offset)->take($limit)->get();
$rows = array();
foreach ($depreciations as $depreciation) {
$actions = '<a href="'.route('update/depreciations', $depreciation->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/depreciations', $depreciation->id).'" data-content="'.trans('admin/depreciations/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($depreciation->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a>';
$rows[] = array(
'id' => $depreciation->id,
'name' => e($depreciation->name),
'months' => e($depreciation->months),
'actions' => $actions
);
}
$data = array('total' => $depreciationsCount, 'rows' => $rows);
return $data;
}
}
+238
View File
@@ -0,0 +1,238 @@
<?php
namespace App\Http\Controllers;
use Config;
use Input;
use Lang;
use Redirect;
use App\Models\Setting;
use Validator;
use View;
use App\Models\Group;
use App\Helpers\Helper;
/**
* This controller handles all actions related to User Groups for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class GroupsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the user group listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Show the page
return View::make('groups/index', compact('groups'));
}
/**
* Returns a view that displays a form to create a new User Group.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::postCreate()
* @since [v1.0]
* @return View
*/
public function getCreate()
{
$group = new Group;
// Get all the available permissions
$permissions = config('permissions');
$groupPermissions = array();
$selectedPermissions = Input::old('permissions', $groupPermissions);
// Show the page
return View::make('groups/edit', compact('permissions', 'selectedPermissions', 'groupPermissions'))->with('group', $group);
}
/**
* Validates and stores the new User Group data.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getCreate()
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
// create a new group instance
$group = new Group();
$group->name = e(Input::get('name'));
$group->permissions = json_encode(Input::get('permission'));
if ($group->save()) {
return redirect()->to("admin/groups")->with('success', trans('admin/groups/message.success.create'));
}
return redirect()->back()->withInput()->withErrors($group->getErrors());
}
/**
* Returns a view that presents a form to edit a User Group.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::postEdit()
* @param int $id
* @since [v1.0]
* @return View
*/
public function getEdit($id = null)
{
$group = Group::find($id);
$permissions = config('permissions');
$groupPermissions = $group->decodePermissions();
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return View::make('groups/edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
/**
* Validates and stores the updated User Group data.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getEdit()
* @param int $id
* @since [v1.0]
* @return Redirect
*/
public function postEdit($id = null)
{
$permissions = config('permissions');
if (!$group = Group::find($id)) {
return redirect()->route('groups')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
$group->name = e(Input::get('name'));
$group->permissions = json_encode(Input::get('permission'));
if (!config('app.lock_passwords')) {
if ($group->save()) {
return redirect()->to("admin/groups")->with('success', trans('admin/groups/message.success.update'));
}
return redirect()->back()->withInput()->withErrors($group->getErrors());
} else {
return redirect()->route('update/group', $id)->withInput()->with('error', 'Denied! Editing groups is not allowed in the demo.');
}
}
/**
* Validates and deletes the User Group.
*
* @author [A. Gianotto] [<snipe@snipe.net]
* @see GroupsController::getEdit()
* @param int $id
* @since [v1.0]
* @return Redirect
*/
public function getDelete($id = null)
{
if (!config('app.lock_passwords')) {
try {
// Get group information
$group = Group::find($id);
$group->delete();
// Redirect to the group management page
return redirect()->route('groups')->with('success', trans('admin/groups/message.success.delete'));
} catch (GroupNotFoundException $e) {
// Redirect to the group management page
return redirect()->route('groups')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
} else {
return redirect()->route('groups')->with('error', trans('general.feature_disabled'));
}
}
/**
* Generates the JSON used to display the User Group listing.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @return String JSON
*/
public function getDatatable()
{
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
if (Input::get('sort')=='name') {
$sort = 'first_name';
} else {
$sort = e(Input::get('sort'));
}
// Grab all the groups
$groups = Group::with('users')->orderBy('name', 'ASC');
//$users = Company::scopeCompanyables($users);
if (Input::has('search')) {
$groups = $users->TextSearch(e(Input::get('search')));
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns =
[
'name','created_at'
];
$sort = in_array($sort, $allowed_columns) ? $sort : 'name';
$groups = $groups->orderBy($sort, $order);
$groupsCount = $groups->count();
$groups = $groups->skip($offset)->take($limit)->get();
$rows = array();
foreach ($groups as $group) {
$group_names = '';
$inout = '';
$actions = '<nobr>';
$actions .= '<a href="' . route('update/group', $group->id) . '" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> ';
if (!config('app.lock_passwords')) {
$actions .= '<a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="' . route('delete/group', $group->id) . '" data-content="'.trans('admin/groups/message.delete.confirm').'" data-title="Delete ' . htmlspecialchars($group->name) . '?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a> ';
} else {
$actions .= ' <span class="btn delete-asset btn-danger btn-sm disabled"><i class="fa fa-trash icon-white"></i></span>';
}
$actions .= '</nobr>';
$rows[] = array(
'id' => $group->id,
'name' => $group->name,
'users' => $group->users->count(),
'created_at' => $group->created_at->format('Y-m-d'),
'actions' => ($actions) ? $actions : '',
);
}
$data = array('total'=>$groupsCount, 'rows'=>$rows);
return $data;
}
}
File diff suppressed because it is too large Load Diff
+432
View File
@@ -0,0 +1,432 @@
<?php
namespace App\Http\Controllers;
use Input;
use Lang;
use App\Models\Location;
use Redirect;
use App\Models\Setting;
use App\Models\User;
use App\Models\Asset;
use DB;
use Str;
use Validator;
use View;
use Auth;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* This controller handles all actions related to Locations for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class LocationsController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the locations listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Grab all the locations
$locations = Location::orderBy('created_at', 'DESC')->with('parent', 'assets', 'assignedassets')->get();
// Show the page
return View::make('locations/index', compact('locations'));
}
/**
* Returns a form view used to create a new location.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::postCreate() method that validates and stores the data
* @since [v1.0]
* @return View
*/
public function getCreate()
{
$locations = Location::orderBy('name', 'ASC')->get();
$location_options_array = Location::getLocationHierarchy($locations);
$location_options = Location::flattenLocationsArray($location_options_array);
$location_options = array('' => 'Top Level') + $location_options;
return View::make('locations/edit')
->with('location_options', $location_options)
->with('location', new Location);
}
/**
* Validates and stores a new location.
*
* @todo Check if a Form Request would work better here.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getCreate() method that makes the form
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
// create a new location instance
$location = new Location();
// Save the location data
$location->name = e(Input::get('name'));
if (Input::get('parent_id')=='') {
$location->parent_id = null;
} else {
$location->parent_id = e(Input::get('parent_id'));
}
$location->currency = e(Input::get('currency', '$'));
$location->address = e(Input::get('address'));
$location->address2 = e(Input::get('address2'));
$location->city = e(Input::get('city'));
$location->state = e(Input::get('state'));
$location->country = e(Input::get('country'));
$location->zip = e(Input::get('zip'));
$location->user_id = Auth::user()->id;
if ($location->save()) {
// Redirect to the new location page
return redirect()->to("admin/settings/locations")->with('success', trans('admin/locations/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($location->getErrors());
}
/**
* Validates and stores a new location created via the Create Asset form modal.
*
* @todo Check if a Form Request would work better here.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see AssetsController::getCreate() method that makes the form
* @since [v1.0]
* @return String JSON
*/
public function store()
{
$new['currency']=Setting::first()->default_currency;
// create a new location instance
$location = new Location();
// Save the location data
$location->name = e(Input::get('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 = e(Input::get('city'));
$location->state = '';//e(Input::get('state'));
$location->country = e(Input::get('country'));
// $location->zip = e(Input::get('zip'));
$location->user_id = Auth::user()->id;
// Was the location created?
if ($location->save()) {
return JsonResponse::create($location);
}
// failure
$errors = $location->errors();
return JsonResponse::create(["error" => "Failed validation: ".print_r($location->getErrors(), true)], 500);
}
/**
* Makes a form view to edit location information.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::postCreate() method that validates and stores
* @param int $locationId
* @since [v1.0]
* @return View
*/
public function getEdit($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'));
}
// Show the page
$locations = Location::orderBy('name', 'ASC')->get();
$location_options_array = Location::getLocationHierarchy($locations);
$location_options = Location::flattenLocationsArray($location_options_array);
$location_options = array('' => 'Top Level') + $location_options;
return View::make('locations/edit', compact('location'))->with('location_options', $location_options);
}
/**
* Validates and stores updated location data from edit form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getEdit() method that makes the form view
* @param int $locationId
* @since [v1.0]
* @return Redirect
*/
public function postEdit($locationId = null)
{
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.does_not_exist'));
}
// Update the location data
$location->name = e(Input::get('name'));
if (Input::get('parent_id')=='') {
$location->parent_id = null;
} else {
$location->parent_id = e(Input::get('parent_id', ''));
}
$location->currency = e(Input::get('currency', '$'));
$location->address = e(Input::get('address'));
$location->address2 = e(Input::get('address2'));
$location->city = e(Input::get('city'));
$location->state = e(Input::get('state'));
$location->country = e(Input::get('country'));
$location->zip = e(Input::get('zip'));
// Was the asset created?
if ($location->save()) {
// Redirect to the saved location page
return redirect()->to("admin/settings/locations/")->with('success', trans('admin/locations/message.update.success'));
}
// Redirect to the location management page
return redirect()->back()->withInput()->withInput()->withErrors($location->getErrors());
}
/**
* Validates and deletes selected location.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v1.0]
* @return Redirect
*/
public function getDelete($locationId)
{
// Check if the location exists
if (is_null($location = Location::find($locationId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.not_found'));
}
if ($location->users->count() > 0) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.assoc_users'));
} elseif ($location->childLocations->count() > 0) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.assoc_child_loc'));
} elseif ($location->assets->count() > 0) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.assoc_assets'));
} elseif ($location->assignedassets->count() > 0) {
return redirect()->to('admin/settings/locations')->with('error', trans('admin/locations/message.assoc_assets'));
} else {
$location->delete();
return redirect()->to('admin/settings/locations')->with('success', trans('admin/locations/message.delete.success'));
}
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the locations detail page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getDataViewUsers() method that returns JSON for location users
* @see LocationsController::getDataViewAssets() method that returns JSON for location assets
* @param int $locationId
* @since [v1.0]
* @return View
*/
public function getView($locationId = null)
{
$location = Location::find($locationId);
if (isset($location->id)) {
return View::make('locations/view', compact('location'));
} else {
// Prepare the error message
$error = trans('admin/locations/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('locations')->with('error', $error);
}
}
/**
* Returns the JSON response to populate the bootstrap tables on the locationa view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getIndex() method that returns JSON for location index
* @since [v1.0]
* @return View
*/
public function getDatatable()
{
$locations = Location::select(array('locations.id','locations.name','locations.address','locations.address2','locations.city','locations.state','locations.zip','locations.country','locations.parent_id','locations.currency'))->with('assets');
if (Input::has('search')) {
$locations = $locations->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
switch (Input::get('sort')) {
case 'parent':
$locations = $locations->OrderParent($order);
break;
default:
$allowed_columns = ['id','name','address','city','state','country','currency'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$locations = $locations->orderBy($sort, $order);
break;
}
$locationsCount = $locations->count();
$locations = $locations->skip($offset)->take($limit)->get();
$rows = array();
foreach ($locations as $location) {
$actions = '<nobr><a href="'.route('update/location', $location->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/location', $location->id).'" data-content="'.trans('admin/locations/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($location->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></nobr>';
$rows[] = array(
'id' => $location->id,
'name' => (string)link_to('admin/settings/locations/'.$location->id.'/view', e($location->name)),
'parent' => ($location->parent) ? e($location->parent->name) : '',
// 'assets' => ($location->assets->count() + $location->assignedassets->count()),
'assets_default' => $location->assignedassets->count(),
'assets_checkedout' => $location->assets->count(),
'address' => ($location->address) ? e($location->address): '',
'city' => e($location->city),
'state' => e($location->state),
'country' => e($location->country),
'currency' => e($location->currency),
'actions' => $actions
);
}
$data = array('total' => $locationsCount, 'rows' => $rows);
return $data;
}
/**
* Returns a JSON response that contains the users association with the
* selected location, to be used by the location detail view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getView() method that creates the display view
* @param int $locationId
* @since [v1.8]
* @return View
*/
public function getDataViewUsers($locationID)
{
$location = Location::find($locationID);
$users = User::where('location_id', '=', $location->id);
if (Input::has('search')) {
$users = $users->TextSearch(e(Input::get('search')));
}
$users = $users->get();
$rows = array();
foreach ($users as $user) {
$rows[] = array(
'name' => (string)link_to('/admin/users/'.$user->id.'/view', e($user->fullName()))
);
}
$data = array('total' => $users->count(), 'rows' => $rows);
return $data;
}
/**
* Returns a JSON response that contains the assets association with the
* selected location, to be used by the location detail view.
*
* @todo This is broken for accessories and consumables.
* @todo This is a very naive implementation. Should clean this up with query scopes.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LocationsController::getView() method that creates the display view
* @param int $locationID
* @since [v1.8]
* @return View
*/
public function getDataViewAssets($locationID)
{
$location = Location::find($locationID)->load('assignedassets.model');
$assets = Asset::AssetsByLocation($location);
if (Input::has('search')) {
$assets = $assets->TextSearch(e(Input::get('search')));
}
$assets = $assets->get();
$rows = array();
foreach ($assets as $asset) {
$rows[] = array(
'name' => (string)link_to(config('app.url').'/hardware/'.$asset->id.'/view', e($asset->showAssetName())),
'asset_tag' => e($asset->asset_tag),
'serial' => e($asset->serial),
'model' => e($asset->model->name),
);
}
$data = array('total' => $assets->count(), 'rows' => $rows);
return $data;
}
}
+327
View File
@@ -0,0 +1,327 @@
<?php
namespace App\Http\Controllers;
use App\Models\Company;
use Input;
use Lang;
use App\Models\Manufacturer;
use Redirect;
use App\Models\Setting;
use Str;
use View;
use Auth;
/**
* This controller handles all actions related to Manufacturers for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ManufacturersController extends Controller
{
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the manufacturers listing, which is generated in getDatatable.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Show the page
return View::make('manufacturers/index', compact('manufacturers'));
}
/**
* Returns a view that displays a form to create a new manufacturer.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::postCreate()
* @since [v1.0]
* @return View
*/
public function getCreate()
{
return View::make('manufacturers/edit')->with('manufacturer', new Manufacturer);
}
/**
* Validates and stores the data for a new manufacturer.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::postCreate()
* @since [v1.0]
* @return Redirect
*/
public function postCreate()
{
$manufacturer = new Manufacturer;
$manufacturer->name = e(Input::get('name'));
$manufacturer->user_id = Auth::user()->id;
if ($manufacturer->save()) {
return redirect()->to("admin/settings/manufacturers")->with('success', trans('admin/manufacturers/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($manufacturer->getErrors());
}
/**
* Returns a view that displays a form to edit a manufacturer.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::postEdit()
* @param int $manufacturerId
* @since [v1.0]
* @return View
*/
public function getEdit($manufacturerId = null)
{
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturer page
return redirect()->to('admin/settings/manufacturers')->with('error', trans('admin/manufacturers/message.does_not_exist'));
}
// Show the page
return View::make('manufacturers/edit', compact('manufacturer'));
}
/**
* Validates and stores the updated manufacturer data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getEdit()
* @param int $manufacturerId
* @since [v1.0]
* @return View
*/
public function postEdit($manufacturerId = null)
{
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturer page
return redirect()->to('admin/settings/manufacturers')->with('error', trans('admin/manufacturers/message.does_not_exist'));
}
// Save the data
$manufacturer->name = e(Input::get('name'));
// Was it created?
if ($manufacturer->save()) {
// Redirect to the new manufacturer page
return redirect()->to("admin/settings/manufacturers")->with('success', trans('admin/manufacturers/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($manufacturer->getErrors());
}
/**
* Deletes a manufacturer.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $manufacturerId
* @since [v1.0]
* @return View
*/
public function getDelete($manufacturerId)
{
// Check if the manufacturer exists
if (is_null($manufacturer = Manufacturer::find($manufacturerId))) {
// Redirect to the manufacturers page
return redirect()->to('admin/settings/manufacturers')->with('error', trans('admin/manufacturers/message.not_found'));
}
if ($manufacturer->has_models() > 0) {
// Redirect to the asset management page
return redirect()->to('admin/settings/manufacturers')->with('error', trans('admin/manufacturers/message.assoc_users'));
} else {
// Delete the manufacturer
$manufacturer->delete();
// Redirect to the manufacturers management page
return redirect()->to('admin/settings/manufacturers')->with('success', trans('admin/manufacturers/message.delete.success'));
}
}
/**
* Returns a view that invokes the ajax tables which actually contains
* the content for the manufacturers detail listing, which is generated in getDatatable.
* 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 View
*/
public function getView($manufacturerId = null)
{
$manufacturer = Manufacturer::find($manufacturerId);
if (isset($manufacturer->id)) {
return View::make('manufacturers/view', compact('manufacturer'));
} else {
// Prepare the error message
$error = trans('admin/manufacturers/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('manufacturers')->with('error', $error);
}
}
/**
* Generates the JSON used to display the manufacturer listings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getIndex()
* @since [v1.0]
* @return String JSON
*/
public function getDatatable()
{
$manufacturers = Manufacturer::select(array('id','name'))->with('assets')
->whereNull('deleted_at');
if (Input::has('search')) {
$manufacturers = $manufacturers->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$manufacturers->orderBy($sort, $order);
$manufacturersCount = $manufacturers->count();
$manufacturers = $manufacturers->skip($offset)->take($limit)->get();
$rows = array();
foreach ($manufacturers as $manufacturer) {
$actions = '<a href="'.route('update/manufacturer', $manufacturer->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/manufacturer', $manufacturer->id).'" data-content="'.trans('admin/manufacturers/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($manufacturer->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a>';
$rows[] = array(
'id' => $manufacturer->id,
'name' => (string)link_to('admin/settings/manufacturers/'.$manufacturer->id.'/view', e($manufacturer->name)),
'assets' => $manufacturer->assets->count(),
'actions' => $actions
);
}
$data = array('total' => $manufacturersCount, 'rows' => $rows);
return $data;
}
/**
* 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
* @since [v1.0]
* @return String JSON
*/
public function getDataView($manufacturerId)
{
$manufacturer = Manufacturer::with('assets.company')->find($manufacturerId);
$manufacturer_assets = $manufacturer->assets;
if (Input::has('search')) {
$manufacturer_assets = $manufacturer_assets->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$allowed_columns = ['id','name','serial','asset_tag'];
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$count = $manufacturer_assets->count();
$rows = array();
foreach ($manufacturer_assets as $asset) {
$actions = '';
if ($asset->deleted_at=='') {
$actions = '<div style=" white-space: nowrap;"><a href="'.route('clone/hardware', $asset->id).'" class="btn btn-info btn-sm" title="Clone asset"><i class="fa fa-files-o"></i></a> <a href="'.route('update/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-pencil icon-white"></i></a> <a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/hardware', $asset->id).'" data-content="'.trans('admin/hardware/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($asset->asset_tag).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a></div>';
} elseif ($asset->deleted_at!='') {
$actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
}
if ($asset->assetstatus) {
if ($asset->assetstatus->deployable != 0) {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) {
$inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>';
} else {
$inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>';
}
}
}
$row = array(
'id' => $asset->id,
'name' => (string)link_to('/hardware/'.$asset->id.'/view', e($asset->showAssetName())),
'model' => e($asset->model->name),
'asset_tag' => e($asset->asset_tag),
'serial' => e($asset->serial),
'assigned_to' => ($asset->assigneduser) ? (string)link_to('/admin/users/'.$asset->assigneduser->id.'/view', e($asset->assigneduser->fullName())): '',
'actions' => $actions,
'companyName' => e(Company::getName($asset)),
);
if (isset($inout)) {
$row['change'] = $inout;
}
$rows[] = $row;
}
$data = array('total' => $count, 'rows' => $rows);
return $data;
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers;
use Image;
use Input;
use Redirect;
use App\Models\Location;
use View;
use Auth;
use App\Helpers\Helper;
/**
* This controller handles all actions related to User Profiles for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ProfileController extends Controller
{
/**
* Returns a view with the user's profile form for editing
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Get the user information
$user = Auth::user();
$location_list = Helper::locationsList();
return View::make('account/profile', compact('user'))->with('location_list', $location_list);
}
/**
* Validates and stores the user's update data.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return Redirect
*/
public function postIndex()
{
// Grab the user
$user = Auth::user();
// Update the user information
$user->first_name = e(Input::get('first_name'));
$user->last_name = e(Input::get('last_name'));
$user->website = e(Input::get('website'));
$user->location_id = e(Input::get('location_id'));
$user->gravatar = e(Input::get('gravatar'));
$user->locale = e(Input::get('locale'));
if (Input::file('avatar')) {
$image = Input::file('avatar');
$file_name = $user->first_name."-".$user->last_name.".".$image->getClientOriginalExtension();
$path = public_path('uploads/avatars/'.$file_name);
Image::make($image->getRealPath())->resize(84, 84)->save($path);
$user->avatar = $file_name;
}
if (Input::get('avatar_delete') == 1 && Input::file('avatar') == "") {
$user->avatar = null;
}
if ($user->save()) {
return redirect()->route('profile')->with('success', 'Account successfully updated');
}
return redirect()->back()->withInput()->withErrors($user->getErrors());
}
}
+824
View File
@@ -0,0 +1,824 @@
<?php
namespace App\Http\Controllers;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use Carbon\Carbon;
use Category;
use App\Models\Company;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\View;
use Input;
use League\Csv\Reader;
use App\Models\License;
use App\Models\Location;
use App\Models\AssetModel;
use Redirect;
use App\Models\Setting;
use App\Models\User;
/**
* This controller handles all actions related to Reports for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ReportsController extends Controller
{
/**
* Returns a view that displaysthe accessories report.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getAccessoryReport()
{
$accessories = Accessory::orderBy('created_at', 'DESC')->with('company')->get();
return View::make('reports/accessories', compact('accessories'));
}
/**
* Exports the accessories to CSV
*
* @deprecated Server-side exports have been replaced by datatables export since v2.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ManufacturersController::getDatatable() method that generates the JSON response
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function exportAccessoryReport()
{
$accessories = Accessory::orderBy('created_at', 'DESC')->get();
$rows = array();
$header = array(
trans('admin/accessories/table.title'),
trans('admin/accessories/general.accessory_category'),
trans('admin/accessories/general.total'),
trans('admin/accessories/general.remaining')
);
$header = array_map('trim', $header);
$rows[] = implode($header, ', ');
// Row per accessory
foreach ($accessories as $accessory) {
$row = array();
$row[] = e($accessory->accessory_name);
$row[] = e($accessory->accessory_category);
$row[] = e($accessory->total);
$row[] = e($accessory->remaining);
$rows[] = implode($row, ',');
}
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
}
/**
* Display asset report.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getAssetsReport()
{
$settings = \App\Models\Setting::first();
// Grab all the assets
$assets = Asset::with(
'model',
'assigneduser.userLoc',
'assetstatus',
'defaultLoc',
'assetlog',
'supplier',
'model.manufacturer',
'company'
)
->orderBy('created_at', 'DESC')
->get();
return View::make('reports/asset', compact('assets'))->with('settings', $settings);
}
/**
* Exports the assets to CSV
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function exportAssetReport()
{
// Grab all the assets
$assets = Asset::orderBy('created_at', 'DESC')->get();
$rows = [ ];
// Create the header row
$header = [
trans('admin/hardware/table.asset_tag'),
trans('admin/hardware/form.manufacturer'),
trans('admin/hardware/form.model'),
trans('general.model_no'),
trans('general.name'),
trans('admin/hardware/table.serial'),
trans('general.status'),
trans('admin/hardware/table.purchase_date'),
trans('admin/hardware/table.purchase_cost'),
trans('admin/hardware/form.order'),
trans('admin/hardware/form.supplier'),
trans('admin/hardware/table.checkoutto'),
trans('admin/hardware/table.location'),
trans('general.notes'),
];
$header = array_map('trim', $header);
$rows[] = implode($header, ',');
// Create a row per asset
foreach ($assets as $asset) {
$row = [ ];
$row[] = e($asset->asset_tag);
if ($asset->model->manufacturer) {
$row[] = e($asset->model->manufacturer->name);
} else {
$row[] = '';
}
$row[] = '"' . e($asset->model->name) . '"';
$row[] = '"' . e($asset->model->modelno) . '"';
$row[] = e($asset->name);
$row[] = e($asset->serial);
if ($asset->assetstatus) {
$row[] = e($asset->assetstatus->name);
} else {
$row[] = '';
}
$row[] = $asset->purchase_date;
$row[] = '"' . number_format($asset->purchase_cost, 2) . '"';
if ($asset->order_number) {
$row[] = e($asset->order_number);
} else {
$row[] = '';
}
if ($asset->supplier_id) {
$row[] = e($asset->supplier->name);
} else {
$row[] = '';
}
if ($asset->assigned_to > 0) {
$user = User::find($asset->assigned_to);
$row[] = e($user->fullName());
} else {
$row[] = ''; // Empty string if unassigned
}
if (( $asset->assigned_to > 0 ) && ( $asset->assigneduser->location_id > 0 )) {
$location = Location::find($asset->assigneduser->location_id);
if ($location) {
$row[] = e($location->name);
} else {
$row[] = '';
}
} elseif ($asset->rtd_location_id) {
$location = Location::find($asset->rtd_location_id);
if ($location->name) {
$row[] = e($location->name);
} else {
$row[] = '';
}
} else {
$row[] = ''; // Empty string if location is not set
}
if ($asset->notes) {
$row[] = '"' . e($asset->notes) . '"';
} else {
$row[] = '';
}
$rows[] = implode($row, ',');
}
// spit out a csv
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
}
/**
* Show depreciation report for assets.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getDeprecationReport()
{
// Grab all the assets
$assets = Asset::with('model', 'assigneduser', 'assetstatus', 'defaultLoc', 'assetlog', 'company')
->orderBy('created_at', 'DESC')->get();
return View::make('reports/depreciation', compact('assets'));
}
/**
* Exports the depreciations to CSV
*
* @deprecated Server-side exports have been replaced by datatables export since v2.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function exportDeprecationReport()
{
// Grab all the assets
$assets = Asset::with('model', 'assigneduser', 'assetstatus', 'defaultLoc', 'assetlog')
->orderBy('created_at', 'DESC')->get();
$csv = \League\Csv\Writer::createFromFileObject(new \SplTempFileObject());
$csv->setOutputBOM(Reader::BOM_UTF16_BE);
$rows = [ ];
// Create the header row
$header = [
trans('admin/hardware/table.asset_tag'),
trans('admin/hardware/table.title'),
trans('admin/hardware/table.serial'),
trans('admin/hardware/table.checkoutto'),
trans('admin/hardware/table.location'),
trans('admin/hardware/table.purchase_date'),
trans('admin/hardware/table.purchase_cost'),
trans('admin/hardware/table.book_value'),
trans('admin/hardware/table.diff')
];
//we insert the CSV header
$csv->insertOne($header);
// Create a row per asset
foreach ($assets as $asset) {
$row = [ ];
$row[] = e($asset->asset_tag);
$row[] = e($asset->name);
$row[] = e($asset->serial);
if ($asset->assigned_to > 0) {
$user = User::find($asset->assigned_to);
$row[] = e($user->fullName());
} else {
$row[] = ''; // Empty string if unassigned
}
if (( $asset->assigned_to > 0 ) && ( $asset->assigneduser->location_id > 0 )) {
$location = Location::find($asset->assigneduser->location_id);
if ($location->city) {
$row[] = e($location->city) . ', ' . e($location->state);
} elseif ($location->name) {
$row[] = e($location->name);
} else {
$row[] = '';
}
} else {
$row[] = ''; // Empty string if location is not set
}
if ($asset->assetloc) {
$currency = e($asset->assetloc->currency);
} else {
$currency = e(Setting::first()->default_currency);
}
$row[] = $asset->purchase_date;
$row[] = $currency . number_format($asset->purchase_cost, 2);
$row[] = $currency . number_format($asset->getDepreciatedValue(), 2);
$row[] = $currency . number_format(( $asset->purchase_cost - $asset->getDepreciatedValue() ), 2);
$csv->insertOne($row);
}
$csv->output('depreciation-report-' . date('Y-m-d') . '.csv');
die;
}
/**
* Displays activity report.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getActivityReport()
{
$log_actions = Actionlog::orderBy('created_at', 'DESC')
->with('adminlog')
->with('accessorylog')
->with('assetlog')
->with('licenselog')
->with('userlog')
->orderBy('created_at', 'DESC')
->get();
return View::make('reports/activity', compact('log_actions'));
}
/**
* Displays license report
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getLicenseReport()
{
$licenses = License::orderBy('created_at', 'DESC')
->with('company')
->get();
return View::make('reports/licenses', compact('licenses'));
}
/**
* Exports the licenses to CSV
*
* @deprecated Server-side exports have been replaced by datatables export since v2.
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function exportLicenseReport()
{
$licenses = License::orderBy('created_at', 'DESC')->get();
$rows = [ ];
$header = [
trans('admin/licenses/table.title'),
trans('admin/licenses/table.serial'),
trans('admin/licenses/form.seats'),
trans('admin/licenses/form.remaining_seats'),
trans('admin/licenses/form.expiration'),
trans('admin/licenses/form.date'),
trans('admin/licenses/form.cost')
];
$header = array_map('trim', $header);
$rows[] = implode($header, ', ');
// Row per license
foreach ($licenses as $license) {
$row = [ ];
$row[] = e($license->name);
$row[] = e($license->serial);
$row[] = e($license->seats);
$row[] = $license->remaincount();
$row[] = $license->expiration_date;
$row[] = $license->purchase_date;
$row[] = '"' . number_format($license->purchase_cost, 2) . '"';
$rows[] = implode($row, ',');
}
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
}
/**
* Returns a form that allows the user to generate a custom CSV report.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ReportsController::postCustomReport() method that generates the CSV
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function getCustomReport()
{
return View::make('reports/custom');
}
/**
* Exports the custom report to CSV
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see ReportsController::getCustomReport() method that generates form view
* @since [v1.0]
* @return \Illuminate\Http\Response
*/
public function postCustom()
{
$assets = Asset::orderBy('created_at', 'DESC')->get();
$rows = [ ];
$header = [ ];
if (e(Input::get('asset_name')) == '1') {
$header[] = 'Asset Name';
}
if (e(Input::get('asset_tag')) == '1') {
$header[] = 'Asset Tag';
}
if (e(Input::get('manufacturer')) == '1') {
$header[] = 'Manufacturer';
}
if (e(Input::get('model')) == '1') {
$header[] = 'Model';
$header[] = 'Model Number';
}
if (e(Input::get('category')) == '1') {
$header[] = 'Category';
}
if (e(Input::get('serial')) == '1') {
$header[] = 'Serial';
}
if (e(Input::get('purchase_date')) == '1') {
$header[] = 'Purchase Date';
}
if (( e(Input::get('purchase_cost')) == '1' ) && ( e(Input::get('depreciation')) != '1' )) {
$header[] = 'Purchase Cost';
}
if (e(Input::get('order')) == '1') {
$header[] = 'Order Number';
}
if (e(Input::get('supplier')) == '1') {
$header[] = 'Supplier';
}
if (e(Input::get('location')) == '1') {
$header[] = 'Location';
}
if (e(Input::get('assigned_to')) == '1') {
$header[] = 'Assigned To';
}
if (e(Input::get('status')) == '1') {
$header[] = 'Status';
}
if (e(Input::get('warranty')) == '1') {
$header[] = 'Warranty';
$header[] = 'Warranty Expires';
}
if (e(Input::get('depreciation')) == '1') {
$header[] = 'Purchase Cost';
$header[] = 'Value';
$header[] = 'Diff';
}
$header = array_map('trim', $header);
$rows[] = implode($header, ',');
foreach ($assets as $asset) {
$row = [ ];
if (e(Input::get('asset_name')) == '1') {
$row[] = '"' .e($asset->name) . '"';
}
if (e(Input::get('asset_tag')) == '1') {
$row[] = e($asset->asset_tag);
}
if (e(Input::get('manufacturer')) == '1') {
if ($asset->model->manufacturer) {
$row[] = '"' .e($asset->model->manufacturer->name) . '"';
} else {
$row[] = '';
}
}
if (e(Input::get('model')) == '1') {
$row[] = '"' . e($asset->model->name) . '"';
$row[] = '"' . e($asset->model->modelno) . '"';
}
if (e(Input::get('category')) == '1') {
$row[] = '"' .e($asset->model->category->name) . '"';
}
if (e(Input::get('serial')) == '1') {
$row[] = e($asset->serial);
}
if (e(Input::get('purchase_date')) == '1') {
$row[] = e($asset->purchase_date);
}
if (e(Input::get('purchase_cost')) == '1' && ( e(Input::get('depreciation')) != '1' )) {
$row[] = '"' . number_format($asset->purchase_cost, 2) . '"';
}
if (e(Input::get('order')) == '1') {
if ($asset->order_number) {
$row[] = e($asset->order_number);
} else {
$row[] = '';
}
}
if (e(Input::get('supplier')) == '1') {
if ($asset->supplier_id) {
$row[] = '"' .e($asset->supplier->name) . '"';
} else {
$row[] = '';
}
}
if (e(Input::get('location')) == '1') {
$show_loc = '';
if (( $asset->assigned_to > 0 ) && ( $asset->assigneduser->location_id !='' )) {
$location = Location::find($asset->assigneduser->location_id);
if ($location) {
$show_loc .= '"' .e($location->name). '"';
} else {
$show_loc .= 'User location '.$asset->assigneduser->location_id.' is invalid';
}
} elseif ($asset->rtd_location_id!='') {
$location = Location::find($asset->rtd_location_id);
if ($location) {
$show_loc .= '"' .e($location->name). '"';
} else {
$show_loc .= 'Default location '.$asset->rtd_location_id.' is invalid';
}
}
$row[] = $show_loc;
}
if (e(Input::get('assigned_to')) == '1') {
if ($asset->assigned_to > 0) {
$user = User::find($asset->assigned_to);
$row[] = '"' .e($user->fullName()). '"';
} else {
$row[] = ''; // Empty string if unassigned
}
}
if (e(Input::get('status')) == '1') {
if (( $asset->status_id == '0' ) && ( $asset->assigned_to == '0' )) {
$row[] = trans('general.ready_to_deploy');
} elseif (( $asset->status_id == '' ) && ( $asset->assigned_to == '0' )) {
$row[] = trans('general.pending');
} elseif ($asset->assetstatus) {
$row[] = '"' .e($asset->assetstatus->name). '"';
} else {
$row[] = '';
}
}
if (e(Input::get('warranty')) == '1') {
if ($asset->warranty_months) {
$row[] = $asset->warranty_months;
$row[] = $asset->warrantee_expires();
} else {
$row[] = '';
$row[] = '';
}
}
if (e(Input::get('depreciation')) == '1') {
$depreciation = $asset->getDepreciatedValue();
$row[] = '"' . number_format($asset->purchase_cost, 2) . '"';
$row[] = '"' . number_format($depreciation, 2) . '"';
$row[] = '"' . number_format($asset->purchase_cost - $depreciation, 2) . '"';
}
$rows[] = implode($row, ',');
}
// spit out a csv
if (array_filter($rows)) {
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
} else {
return redirect()->to("reports/custom")
->with('error', trans('admin/reports/message.error'));
}
}
/**
* getImprovementsReport
*
* @return View
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function getAssetMaintenancesReport()
{
// Grab all the improvements
$assetMaintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company')
->orderBy('created_at', 'DESC')
->get();
return View::make('reports/asset_maintenances', compact('assetMaintenances'));
}
/**
* exportImprovementsReport
*
* @return \Illuminate\Http\Response
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function exportAssetMaintenancesReport()
{
// Grab all the improvements
$assetMaintenances = AssetMaintenance::with('asset', 'supplier')
->orderBy('created_at', 'DESC')
->get();
$rows = [ ];
$header = [
trans('admin/asset_maintenances/table.asset_name'),
trans('admin/asset_maintenances/table.supplier_name'),
trans('admin/asset_maintenances/form.asset_maintenance_type'),
trans('admin/asset_maintenances/form.title'),
trans('admin/asset_maintenances/form.start_date'),
trans('admin/asset_maintenances/form.completion_date'),
trans('admin/asset_maintenances/form.asset_maintenance_time'),
trans('admin/asset_maintenances/form.cost')
];
$header = array_map('trim', $header);
$rows[] = implode($header, ',');
foreach ($assetMaintenances as $assetMaintenance) {
$row = [ ];
$row[] = str_replace(',', '', e($assetMaintenance->asset->name));
$row[] = str_replace(',', '', e($assetMaintenance->supplier->name));
$row[] = e($assetMaintenance->improvement_type);
$row[] = e($assetMaintenance->title);
$row[] = e($assetMaintenance->start_date);
$row[] = e($assetMaintenance->completion_date);
if (is_null($assetMaintenance->asset_maintenance_time)) {
$improvementTime = intval(Carbon::now()
->diffInDays(Carbon::parse($assetMaintenance->start_date)));
} else {
$improvementTime = intval($assetMaintenance->asset_maintenance_time);
}
$row[] = $improvementTime;
$row[] = trans('general.currency') . number_format($assetMaintenance->cost, 2);
$rows[] = implode($row, ',');
}
// spit out a csv
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
}
/**
* getAssetAcceptanceReport
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function getAssetAcceptanceReport()
{
$assetsForReport = Asset::notYetAccepted()->with('company')->get();
return View::make('reports/unaccepted_assets', compact('assetsForReport'));
}
/**
* exportAssetAcceptanceReport
*
* @return \Illuminate\Http\Response
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function exportAssetAcceptanceReport()
{
// Grab all the improvements
$assetsForReport = Actionlog::whereIn('id', $this->getAssetsNotAcceptedYet())
->get();
$rows = [ ];
$header = [
trans('general.category'),
trans('admin/hardware/form.model'),
trans('admin/hardware/form.name'),
trans('admin/hardware/table.asset_tag'),
trans('admin/hardware/table.checkoutto'),
];
$header = array_map('trim', $header);
$rows[] = implode($header, ',');
foreach ($assetsForReport as $assetItem) {
$row = [ ];
$row[] = str_replace(',', '', e($assetItem->assetlog->model->category->name));
$row[] = str_replace(',', '', e($assetItem->assetlog->model->name));
$row[] = str_replace(',', '', e($assetItem->assetlog->showAssetName()));
$row[] = str_replace(',', '', e($assetItem->assetlog->asset_tag));
$row[] = str_replace(',', '', e($assetItem->assetlog->assigneduser->fullName()));
$rows[] = implode($row, ',');
}
// spit out a csv
$csv = implode($rows, "\n");
$response = Response::make($csv, 200);
$response->header('Content-Type', 'text/csv');
$response->header('Content-disposition', 'attachment;filename=report.csv');
return $response;
}
/**
* getCheckedOutAssetsRequiringAcceptance
*
* @param $modelsInCategoriesThatRequireAcceptance
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getCheckedOutAssetsRequiringAcceptance($modelsInCategoriesThatRequireAcceptance)
{
$assets = Asset::deployed()
->inModelList($modelsInCategoriesThatRequireAcceptance)
->select('id')
->get()
->toArray();
return array_pluck($assets, 'id');
}
/**
* getModelsInCategoriesThatRequireAcceptance
*
* @param $assetCategoriesRequiringAcceptance
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getModelsInCategoriesThatRequireAcceptance($assetCategoriesRequiringAcceptance)
{
return array_pluck(Model::inCategory($assetCategoriesRequiringAcceptance)
->select('id')
->get()
->toArray(), 'id');
}
/**
* getCategoriesThatRequireAcceptance
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getCategoriesThatRequireAcceptance()
{
return array_pluck(Category::requiresAcceptance()
->select('id')
->get()
->toArray(), 'id');
}
/**
* getAssetsCheckedOutRequiringAcceptance
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getAssetsCheckedOutRequiringAcceptance()
{
return $this->getCheckedOutAssetsRequiringAcceptance(
$this->getModelsInCategoriesThatRequireAcceptance($this->getCategoriesThatRequireAcceptance())
);
}
/**
* getAssetsNotAcceptedYet
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
protected function getAssetsNotAcceptedYet()
{
return Asset::unaccepted();
}
}
+589
View File
@@ -0,0 +1,589 @@
<?php
namespace App\Http\Controllers;
use Input;
use Lang;
use App\Models\Setting;
use App\Models\Ldap;
use Redirect;
use DB;
use Str;
use View;
use Image;
use Config;
use Response;
use Artisan;
use Crypt;
use Mail;
use App\Models\User;
use App\Http\Requests\SetupUserRequest;
/**
* This controller handles all actions related to Settings for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class SettingsController extends Controller
{
/**
* Checks to see whether or not the database has a migrations table
* and a user, otherwise display the setup view.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return View
*/
public function getSetupIndex()
{
try {
$conn = DB::select('select 2 + 2');
$start_settings['db_conn'] = true;
$start_settings['db_name'] = DB::connection()->getDatabaseName();
$start_settings['db_error'] = null;
} catch (\PDOException $e) {
$start_settings['db_conn'] = false;
$start_settings['db_name'] = config('database.connections.mysql.database');
$start_settings['db_error'] = $e->getMessage();
}
$protocol = array_key_exists('HTTPS', $_SERVER) && ( $_SERVER['HTTPS'] == "on") ? 'https://' : 'http://';
$pageURL = $protocol;
if ($_SERVER["SERVER_PORT"] != "80") {
$main_page = $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"];
$pageURL .= $main_page.$_SERVER["REQUEST_URI"];
} else {
$main_page = $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
$pageURL .= $main_page;
}
$start_settings['env_location'] = $pageURL.'../.env';
if (config('app.url').'/setup'!=$pageURL) {
$start_settings['url_valid']= false;
} else {
$start_settings['url_valid']= true;
}
$start_settings['url_config']= config('app.url');
$start_settings['real_url']= $pageURL;
$exposed_env = @file_get_contents($main_page.'/.env');
if ($exposed_env) {
$start_settings['env_exposed'] = true;
} else {
$start_settings['env_exposed'] = false;
}
if (\App::Environment('production') && (config('app.debug')==true)) {
$start_settings['debug_exposed'] = true;
} else {
$start_settings['debug_exposed'] = false;
}
$environment = app()->environment();
if ($environment!='production') {
$start_settings['env'] = $environment;
$start_settings['prod'] = false;
} else {
$start_settings['env'] = $environment;
$start_settings['prod'] = true;
}
if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER["SCRIPT_FILENAME"]));
$start_settings['owner'] = $owner['name'];
} else { // Windows
// TODO: Is there a way of knowing if a windows user has elevated permissions
// This just gets the user name, which likely isn't 'root'
// $start_settings['owner'] = getenv('USERNAME');
$start_settings['owner'] = '';
}
if (($start_settings['owner']==='root') || ($start_settings['owner']==='0')) {
$start_settings['owner_is_admin'] = true;
} else {
$start_settings['owner_is_admin'] = false;
}
if ((is_writable(storage_path()))
&& (is_writable(storage_path().'/framework'))
&& (is_writable(storage_path().'/framework/cache'))
&& (is_writable(storage_path().'/framework/sessions'))
&& (is_writable(storage_path().'/framework/views'))
&& (is_writable(storage_path().'/logs'))
) {
$start_settings['writable'] = true;
} else {
$start_settings['writable'] = false;
}
$start_settings['gd'] = extension_loaded('gd');
return View::make('setup/index')
->with('step', 1)
->with('start_settings', $start_settings)
->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->subject('Test Email from Snipe-IT');
});
return 'success';
} catch (Exception $e) {
return 'error';
}
}
/**
* Save the first admin user from Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
*/
public function postSaveFirstAdmin(SetupUserRequest $request)
{
$user = new User;
$user->first_name = $data['first_name']= e(Input::get('first_name'));
$user->last_name = e(Input::get('last_name'));
$user->email = $data['email'] = e(Input::get('email'));
$user->activated = 1;
$permissions = array('superuser' => 1);
$user->permissions = json_encode($permissions);
$user->username = $data['username'] = e(Input::get('username'));
$user->password = bcrypt(Input::get('password'));
$data['password'] = Input::get('password');
$settings = new Setting;
$settings->site_name = e(Input::get('site_name'));
$settings->alert_email = e(Input::get('email'));
$settings->alerts_enabled = 1;
$settings->brand = 1;
$settings->locale = 'en';
$settings->default_currency = 'USD';
$settings->user_id = 1;
$settings->email_domain = e(Input::get('email_domain'));
$settings->email_format = e(Input::get('email_format'));
if ((!$user->isValid()) || (!$settings->isValid())) {
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
} else {
$user->save();
$settings->save();
if (Input::get('email_creds')=='1') {
Mail::send(['text' => 'emails.firstadmin'], $data, function ($m) use ($data) {
$m->to($data['email'], $data['first_name']);
$m->subject('Your Snipe-IT credentials');
});
}
return redirect()->route('setup.done');
}
}
/**
* Return the admin user creation form in Setup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return View
*/
public function getSetupUser()
{
return View::make('setup/user')
->with('step', 3)
->with('section', 'Create a User');
}
/**
* Return the view that tells the user that the Setup is done.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return View
*/
public function getSetupDone()
{
return View::make('setup/done')
->with('step', 4)
->with('section', 'Done!');
}
/**
* Migrate the database tables, and return the output
* to a view for Setup
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return View
*/
public function getSetupMigrate()
{
Artisan::call('migrate', ['--force' => true]);
$output = Artisan::output();
return View::make('setup/migrate')
->with('output', $output)
->with('step', 2)
->with('section', 'Create Database Tables');
}
/**
* Return a view that shows some of the key settings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getIndex()
{
// Grab all the settings
$settings = Setting::all();
// Show the page
return View::make('settings/index', compact('settings'));
}
/**
* Return a form to allow a super admin to update settings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return View
*/
public function getEdit()
{
$setting = Setting::first();
$is_gd_installed = extension_loaded('gd');
return View::make('settings/edit', compact('setting'))->with('is_gd_installed', $is_gd_installed);
}
/**
* Validate and process settings edit form.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @return Redirect
*/
public function postEdit()
{
// Check if the asset exists
if (is_null($setting = Setting::first())) {
// Redirect to the asset management page with error
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
if (Input::get('clear_logo')=='1') {
$setting->logo = null;
} elseif (Input::file('logo_img')) {
if (!config('app.lock_passwords')) {
$image = Input::file('logo_img');
$file_name = "logo.".$image->getClientOriginalExtension();
$path = public_path('uploads/'.$file_name);
Image::make($image->getRealPath())->resize(null, 40, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$setting->logo = $file_name;
}
}
if (config('app.lock_passwords')==false) {
$setting->site_name = e(Input::get('site_name'));
$setting->brand = e(Input::get('brand'));
$setting->custom_css = e(Input::get('custom_css'));
}
if (Input::get('per_page')!='') {
$setting->per_page = e(Input::get('per_page'));
} else {
$setting->per_page = 200;
}
$setting->locale = e(Input::get('locale', 'en'));
$setting->qr_code = e(Input::get('qr_code', '0'));
$setting->full_multiple_companies_support = e(Input::get('full_multiple_companies_support', '0'));
$setting->alt_barcode = e(Input::get('alt_barcode'));
$setting->alt_barcode_enabled = e(Input::get('alt_barcode_enabled', '0'));
$setting->barcode_type = e(Input::get('barcode_type'));
$setting->load_remote = e(Input::get('load_remote', '0'));
$setting->default_currency = e(Input::get('default_currency', '$'));
$setting->qr_text = e(Input::get('qr_text'));
$setting->auto_increment_prefix = e(Input::get('auto_increment_prefix'));
$setting->auto_increment_assets = e(Input::get('auto_increment_assets', '0'));
$setting->alert_interval = e(Input::get('alert_interval'));
$setting->alert_threshold = e(Input::get('alert_threshold'));
$setting->email_domain = e(Input::get('email_domain'));
$setting->email_format = e(Input::get('email_format'));
$setting->username_format = e(Input::get('username_format'));
$setting->labels_per_page = e(Input::get('labels_per_page'));
$setting->labels_width = e(Input::get('labels_width'));
$setting->labels_height = e(Input::get('labels_height'));
$setting->labels_pmargin_left = e(Input::get('labels_pmargin_left'));
$setting->labels_pmargin_right = e(Input::get('labels_pmargin_right'));
$setting->labels_pmargin_top = e(Input::get('labels_pmargin_top'));
$setting->labels_pmargin_bottom = e(Input::get('labels_pmargin_bottom'));
$setting->labels_display_bgutter = e(Input::get('labels_display_bgutter'));
$setting->labels_display_sgutter = e(Input::get('labels_display_sgutter'));
$setting->labels_fontsize = e(Input::get('labels_fontsize'));
$setting->labels_pagewidth = e(Input::get('labels_pagewidth'));
$setting->labels_pageheight = e(Input::get('labels_pageheight'));
if (Input::has('labels_display_name')) {
$setting->labels_display_name = 1;
} else {
$setting->labels_display_name = 0;
}
if (Input::has('labels_display_serial')) {
$setting->labels_display_serial = 1;
} else {
$setting->labels_display_serial = 0;
}
if (Input::has('labels_display_tag')) {
$setting->labels_display_tag = 1;
} else {
$setting->labels_display_tag = 0;
}
$alert_email = rtrim(Input::get('alert_email'), ',');
$alert_email = trim(Input::get('alert_email'));
$setting->alert_email = e($alert_email);
$setting->alerts_enabled = e(Input::get('alerts_enabled', '0'));
$setting->header_color = e(Input::get('header_color'));
$setting->default_eula_text = e(Input::get('default_eula_text'));
$setting->slack_endpoint = e(Input::get('slack_endpoint'));
$setting->slack_channel = e(Input::get('slack_channel'));
$setting->slack_botname = e(Input::get('slack_botname'));
$setting->ldap_enabled = e(Input::get('ldap_enabled', '0'));
$setting->ldap_server = e(Input::get('ldap_server'));
$setting->ldap_server_cert_ignore = e(Input::get('ldap_server_cert_ignore', false));
$setting->ldap_uname = e(Input::get('ldap_uname'));
if (Input::has('ldap_pword')) {
$setting->ldap_pword = Crypt::encrypt(Input::get('ldap_pword'));
}
$setting->ldap_basedn = e(Input::get('ldap_basedn'));
$setting->ldap_filter = Input::get('ldap_filter');
$setting->ldap_username_field = Input::get('ldap_username_field');
$setting->ldap_lname_field = e(Input::get('ldap_lname_field'));
$setting->ldap_fname_field = e(Input::get('ldap_fname_field'));
$setting->ldap_auth_filter_query = Input::get('ldap_auth_filter_query');
$setting->ldap_version = e(Input::get('ldap_version'));
$setting->ldap_active_flag = e(Input::get('ldap_active_flag'));
$setting->ldap_emp_num = e(Input::get('ldap_emp_num'));
$setting->ldap_email = e(Input::get('ldap_email'));
$setting->ad_domain = e(Input::get('ad_domain'));
$setting->is_ad = e(Input::get('is_ad', '0'));
// If validation fails, we'll exit the operation now.
if ($setting->save()) {
return redirect()->to("admin/settings/app")->with('success', trans('admin/settings/message.update.success'));
} else {
return redirect()->back()->withInput()->withErrors($setting->getErrors());
}
// Redirect to the setting management page
return redirect()->to("admin/settings/app/edit")->with('error', trans('admin/settings/message.update.error'));
}
public function getLdapTest() {
try {
$connection = Ldap::connectToLdap();
try {
Ldap::bindAdminToLdap($connection);
return response()->json(['message' => 'It worked!'], 200);
} catch (\Exception $e) {
return response()->json(['message' => $e->getMessage()], 500);
}
return response()->json(['message' => 'It worked!'], 200);
} catch (\Exception $e) {
return response()->json(['message' => $e->getMessage()], 500);
}
}
/**
* Show the listing of backups
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.8]
* @return View
*/
public function getBackups()
{
$path = storage_path().'/app/'.config('laravel-backup.backup.name');
$files = array();
if ($handle = opendir($path)) {
/* This is the correct way to loop over the directory. */
while (false !== ($entry = readdir($handle))) {
clearstatcache();
if (substr(strrchr($entry, '.'), 1)=='zip') {
$files[] = array(
'filename' => $entry,
'filesize' => Setting::fileSizeConvert(filesize($path.'/'.$entry)),
'modified' => filemtime($path.'/'.$entry)
);
}
}
closedir($handle);
$files = array_reverse($files);
}
return View::make('settings/backups', compact('path', 'files'));
}
/**
* Process the backup.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.8]
* @return Redirect
*/
public function postBackups()
{
if (!config('app.lock_passwords')) {
Artisan::call('backup:run');
return redirect()->to("admin/settings/backups")->with('success', trans('admin/settings/message.backup.generated'));
} else {
return redirect()->to("admin/settings/backups")->with('error', trans('general.feature_disabled'));
}
}
/**
* Download the backup file
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.8]
* @return Redirect
*/
public function downloadFile($filename = null)
{
if (!config('app.lock_passwords')) {
$path = storage_path().'/app/'.config('laravel-backup.backup.name');
$file = $path.'/'.$filename;
if (file_exists($file)) {
return Response::download($file);
} else {
// Redirect to the backup page
return redirect()->route('settings/backups')->with('error', trans('admin/settings/message.backup.file_not_found'));
}
} else {
// Redirect to the backup page
return redirect()->route('settings/backups')->with('error', trans('general.feature_disabled'));
}
}
/**
* Delete the backup file
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.8]
* @return View
*/
public function deleteFile($filename = null)
{
if (!config('app.lock_passwords')) {
$path = storage_path().'/app/'.config('laravel-backup.backup.name');
$file = $path.'/'.$filename;
if (file_exists($file)) {
unlink($file);
return redirect()->route('settings/backups')->with('success', trans('admin/settings/message.backup.file_deleted'));
} else {
return redirect()->route('settings/backups')->with('error', trans('admin/settings/message.backup.file_not_found'));
}
} else {
return redirect()->route('settings/backups')->with('error', trans('general.feature_disabled'));
}
}
/**
* Purges soft-deletes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return View
*/
public function postPurge()
{
if (!config('app.lock_passwords')) {
if (Input::get('confirm_purge')=='DELETE') {
Artisan::call('snipeit:purge', ['--force'=>'true','--no-interaction'=>true]);
$output = Artisan::output();
return View::make('settings/purge')
->with('output', $output)->with('success', trans('admin/settings/message.purge.success'));
} else {
return redirect()->back()->with('error', trans('admin/settings/message.purge.validation_failed'));
}
} else {
return redirect()->back()->with('error', trans('general.feature_disabled'));
}
}
}
+307
View File
@@ -0,0 +1,307 @@
<?php
namespace App\Http\Controllers;
use Input;
use Lang;
use App\Models\Statuslabel;
use App\Models\Asset;
use Redirect;
use DB;
use App\Models\Setting;
use Str;
use View;
use App\Helpers\Helper;
use Auth;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* This controller handles all actions related to Status Labels for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class StatuslabelsController extends Controller
{
/**
* Show a list of all the statuslabels.
*
* @return View
*/
public function getIndex()
{
// Show the page
return View::make('statuslabels/index', compact('statuslabels'));
}
/**
* Show a count of assets by status label
*
* @return View
*/
public function getAssetCountByStatuslabel()
{
$colors = [];
$statuslabels = Statuslabel::get();
$labels=[];
$points=[];
foreach ($statuslabels as $statuslabel) {
$labels[]=$statuslabel->name;
$points[]=$statuslabel->assets()->whereNull('assigned_to')->count();
}
$labels[]='Deployed';
$points[]=Asset::whereNotNull('assigned_to')->count();
$result= [
"labels" => $labels,
"datasets" => [ [
"data" => $points,
"backgroundColor" => Helper::chartColors(),
"hoverBackgroundColor" => Helper::chartColors()
]]
];
return $result;
}
/**
* Statuslabel create.
*
* @return View
*/
public function getCreate()
{
// Show the page
$statuslabel = new Statuslabel;
$use_statuslabel_type = $statuslabel->getStatuslabelType();
$statuslabel_types = Helper::statusTypeList();
return View::make('statuslabels/edit', compact('statuslabel_types', 'statuslabel'))->with('use_statuslabel_type', $use_statuslabel_type);
}
/**
* Statuslabel create form processing.
*
* @return Redirect
*/
public function postCreate(Request $request)
{
// create a new model instance
$statuslabel = new Statuslabel();
if (!$request->has('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
$statustype = Statuslabel::getStatuslabelTypesForDB($request->input('statuslabel_types'));
// Save the Statuslabel data
$statuslabel->name = e(Input::get('name'));
$statuslabel->user_id = Auth::user()->id;
$statuslabel->notes = e(Input::get('notes'));
$statuslabel->deployable = $statustype['deployable'];
$statuslabel->pending = $statustype['pending'];
$statuslabel->archived = $statustype['archived'];
// Was the asset created?
if ($statuslabel->save()) {
// Redirect to the new Statuslabel page
return redirect()->to("admin/settings/statuslabels")->with('success', trans('admin/statuslabels/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($statuslabel->getErrors());
}
public function store(Request $request)
{
$statuslabel = new Statuslabel();
if (!$request->has('statuslabel_types')) {
return JsonResponse::create(["error" => trans('validation.statuslabel_type')], 500);
}
$statustype = Statuslabel::getStatuslabelTypesForDB(Input::get('statuslabel_types'));
$statuslabel->name = e(Input::get('name'));
$statuslabel->user_id = Auth::user()->id;
$statuslabel->notes = '';
$statuslabel->deployable = $statustype['deployable'];
$statuslabel->pending = $statustype['pending'];
$statuslabel->archived = $statustype['archived'];
if ($statuslabel->isValid()) {
$statuslabel->save();
// Redirect to the new Statuslabel page
return JsonResponse::create($statuslabel);
}
return JsonResponse::create(["error" => $statuslabel->getErrors()->first()], 500);
}
/**
* Statuslabel update.
*
* @param int $statuslabelId
* @return View
*/
public function getEdit($statuslabelId = null)
{
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/statuslabels')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
$use_statuslabel_type = $statuslabel->getStatuslabelType();
$statuslabel_types = array('' => trans('admin/hardware/form.select_statustype')) + array('undeployable' => trans('admin/hardware/general.undeployable')) + array('pending' => trans('admin/hardware/general.pending')) + array('archived' => trans('admin/hardware/general.archived')) + array('deployable' => trans('admin/hardware/general.deployable'));
return View::make('statuslabels/edit', compact('statuslabel', 'statuslabel_types'))->with('use_statuslabel_type', $use_statuslabel_type);
}
/**
* Statuslabel update form processing page.
*
* @param int $statuslabelId
* @return Redirect
*/
public function postEdit(Request $request, $statuslabelId = null)
{
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/statuslabels')->with('error', trans('admin/statuslabels/message.does_not_exist'));
}
if (!$request->has('statuslabel_types')) {
return redirect()->back()->withInput()->withErrors(['statuslabel_types' => trans('validation.statuslabel_type')]);
}
// Update the Statuslabel data
$statustype = Statuslabel::getStatuslabelTypesForDB(Input::get('statuslabel_types'));
$statuslabel->name = e(Input::get('name'));
$statuslabel->notes = e(Input::get('notes'));
$statuslabel->deployable = $statustype['deployable'];
$statuslabel->pending = $statustype['pending'];
$statuslabel->archived = $statustype['archived'];
// Was the asset created?
if ($statuslabel->save()) {
// Redirect to the saved Statuslabel page
return redirect()->to("admin/settings/statuslabels/")->with('success', trans('admin/statuslabels/message.update.success'));
} else {
return redirect()->back()->withInput()->withErrors($statuslabel->getErrors());
}
// Redirect to the Statuslabel management page
return redirect()->to("admin/settings/statuslabels/$statuslabelId/edit")->with('error', trans('admin/statuslabels/message.update.error'));
}
/**
* Delete the given Statuslabel.
*
* @param int $statuslabelId
* @return Redirect
*/
public function getDelete($statuslabelId)
{
// Check if the Statuslabel exists
if (is_null($statuslabel = Statuslabel::find($statuslabelId))) {
// Redirect to the blogs management page
return redirect()->to('admin/settings/statuslabels')->with('error', trans('admin/statuslabels/message.not_found'));
}
if ($statuslabel->has_assets() > 0) {
// Redirect to the asset management page
return redirect()->to('admin/settings/statuslabels')->with('error', trans('admin/statuslabels/message.assoc_assets'));
} else {
$statuslabel->delete();
// Redirect to the statuslabels management page
return redirect()->to('admin/settings/statuslabels')->with('success', trans('admin/statuslabels/message.delete.success'));
}
}
public function getDatatable()
{
$statuslabels = Statuslabel::select(array('id','name','deployable','pending','archived'))
->whereNull('deleted_at');
if (Input::has('search')) {
$statuslabels = $statuslabels->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$statuslabels->orderBy($sort, $order);
$statuslabelsCount = $statuslabels->count();
$statuslabels = $statuslabels->skip($offset)->take($limit)->get();
$rows = array();
foreach ($statuslabels as $statuslabel) {
if ($statuslabel->deployable == 1) {
$label_type = trans('admin/statuslabels/table.deployable');
} elseif ($statuslabel->pending == 1) {
$label_type = trans('admin/statuslabels/table.pending');
} elseif ($statuslabel->archived == 1) {
$label_type = trans('admin/statuslabels/table.archived');
} else {
$label_type = trans('admin/statuslabels/table.undeployable');
}
$actions = '<a href="'.route('update/statuslabel', $statuslabel->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/statuslabel', $statuslabel->id).'" data-content="'.trans('admin/statuslabels/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($statuslabel->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a>';
$rows[] = array(
'id' => e($statuslabel->id),
'type' => e($label_type),
'name' => e($statuslabel->name),
'actions' => $actions
);
}
$data = array('total' => $statuslabelsCount, 'rows' => $rows);
return $data;
}
}
+297
View File
@@ -0,0 +1,297 @@
<?php
namespace App\Http\Controllers;
use Image;
use App\Models\AssetMaintenance;
use Input;
use Lang;
use App\Models\Supplier;
use Redirect;
use App\Models\Setting;
use Str;
use View;
use Auth;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* This controller handles all actions related to Suppliers for
* the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class SuppliersController extends Controller
{
/**
* Show a list of all suppliers
*
* @return View
*/
public function getIndex()
{
// Grab all the suppliers
$suppliers = Supplier::orderBy('created_at', 'DESC')->get();
// Show the page
return View::make('suppliers/index', compact('suppliers'));
}
/**
* Supplier create.
*
* @return View
*/
public function getCreate()
{
return View::make('suppliers/edit')->with('supplier', new Supplier);
}
/**
* Supplier create form processing.
*
* @return Redirect
*/
public function postCreate()
{
// get the POST data
$new = Input::all();
// Create a new supplier
$supplier = new Supplier;
// Save the location data
$supplier->name = e(Input::get('name'));
$supplier->address = e(Input::get('address'));
$supplier->address2 = e(Input::get('address2'));
$supplier->city = e(Input::get('city'));
$supplier->state = e(Input::get('state'));
$supplier->country = e(Input::get('country'));
$supplier->zip = e(Input::get('zip'));
$supplier->contact = e(Input::get('contact'));
$supplier->phone = e(Input::get('phone'));
$supplier->fax = e(Input::get('fax'));
$supplier->email = e(Input::get('email'));
$supplier->notes = e(Input::get('notes'));
$supplier->url = $supplier->addhttp(e(Input::get('url')));
$supplier->user_id = Auth::user()->id;
if (Input::file('image')) {
$image = Input::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) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$supplier->image = $file_name;
}
// Was it created?
if ($supplier->save()) {
// Redirect to the new supplier page
return redirect()->to("admin/settings/suppliers")->with('success', trans('admin/suppliers/message.create.success'));
}
return redirect()->back()->withInput()->withErrors($supplier->getErrors());
}
public function store(Request $request)
{
$supplier = new Supplier;
$supplier->name = e($request->input('name'));
$supplier->user_id = Auth::user()->id;
if ($supplier->save()) {
return JsonResponse::create($supplier);
}
return JsonResponse::create(["error" => "Failed validation: ".print_r($supplier->getErrors(), true)], 500);
return JsonResponse::create(["error" => "Couldn't save Supplier"]);
}
/**
* Supplier update.
*
* @param int $supplierId
* @return View
*/
public function getEdit($supplierId = null)
{
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
// Redirect to the supplier page
return redirect()->to('admin/settings/suppliers')->with('error', trans('admin/suppliers/message.does_not_exist'));
}
// Show the page
return View::make('suppliers/edit', compact('supplier'));
}
/**
* Supplier update form processing page.
*
* @param int $supplierId
* @return Redirect
*/
public function postEdit($supplierId = null)
{
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
// Redirect to the supplier page
return redirect()->to('admin/settings/suppliers')->with('error', trans('admin/suppliers/message.does_not_exist'));
}
// Save the data
$supplier->name = e(Input::get('name'));
$supplier->address = e(Input::get('address'));
$supplier->address2 = e(Input::get('address2'));
$supplier->city = e(Input::get('city'));
$supplier->state = e(Input::get('state'));
$supplier->country = e(Input::get('country'));
$supplier->zip = e(Input::get('zip'));
$supplier->contact = e(Input::get('contact'));
$supplier->phone = e(Input::get('phone'));
$supplier->fax = e(Input::get('fax'));
$supplier->email = e(Input::get('email'));
$supplier->url = $supplier->addhttp(e(Input::get('url')));
$supplier->notes = e(Input::get('notes'));
if (Input::file('image')) {
$image = Input::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) {
$constraint->aspectRatio();
$constraint->upsize();
})->save($path);
$supplier->image = $file_name;
}
if (Input::get('image_delete') == 1 && Input::file('image') == "") {
$supplier->image = null;
}
if ($supplier->save()) {
return redirect()->to("admin/settings/suppliers")->with('success', trans('admin/suppliers/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($supplier->getErrors());
}
/**
* Delete the given supplier.
*
* @param int $supplierId
* @return Redirect
*/
public function getDelete($supplierId)
{
// Check if the supplier exists
if (is_null($supplier = Supplier::find($supplierId))) {
// Redirect to the suppliers page
return redirect()->to('admin/settings/suppliers')->with('error', trans('admin/suppliers/message.not_found'));
}
if ($supplier->num_assets() > 0) {
// Redirect to the asset management page
return redirect()->to('admin/settings/suppliers')->with('error', trans('admin/suppliers/message.assoc_users'));
} else {
// Delete the supplier
$supplier->delete();
// Redirect to the suppliers management page
return redirect()->to('admin/settings/suppliers')->with('success', trans('admin/suppliers/message.delete.success'));
}
}
/**
* Get the asset information to present to the supplier view page
*
* @param int $assetId
* @return View
**/
public function getView($supplierId = null)
{
$supplier = Supplier::find($supplierId);
if (isset($supplier->id)) {
return View::make('suppliers/view', compact('supplier'));
} else {
// Prepare the error message
$error = trans('admin/suppliers/message.does_not_exist', compact('id'));
// Redirect to the user management page
return redirect()->route('suppliers')->with('error', $error);
}
}
public function getDatatable()
{
$suppliers = Supplier::select(array('id','name','address','address2','city','state','country','fax', 'phone','email','contact'))
->whereNull('deleted_at');
if (Input::has('search')) {
$suppliers = $suppliers->TextSearch(e(Input::get('search')));
}
if (Input::has('offset')) {
$offset = e(Input::get('offset'));
} else {
$offset = 0;
}
if (Input::has('limit')) {
$limit = e(Input::get('limit'));
} else {
$limit = 50;
}
$allowed_columns = ['id','name','address','phone','contact','fax','email'];
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'created_at';
$suppliers->orderBy($sort, $order);
$suppliersCount = $suppliers->count();
$suppliers = $suppliers->skip($offset)->take($limit)->get();
$rows = array();
foreach ($suppliers as $supplier) {
$actions = '<a href="'.route('update/supplier', $supplier->id).'" class="btn btn-warning btn-sm" style="margin-right:5px;"><i class="fa fa-pencil icon-white"></i></a><a data-html="false" class="btn delete-asset btn-danger btn-sm" data-toggle="modal" href="'.route('delete/supplier', $supplier->id).'" data-content="'.trans('admin/suppliers/message.delete.confirm').'" data-title="'.trans('general.delete').' '.htmlspecialchars($supplier->name).'?" onClick="return false;"><i class="fa fa-trash icon-white"></i></a>';
$rows[] = array(
'id' => $supplier->id,
'name' => (string)link_to('admin/settings/suppliers/'.$supplier->id.'/view', e($supplier->name)),
'contact' => e($supplier->contact),
'address' => e($supplier->address).' '.e($supplier->address2).' '.e($supplier->city).' '.e($supplier->state).' '.e($supplier->country),
'phone' => e($supplier->phone),
'fax' => e($supplier->fax),
'email' => ($supplier->email!='') ? '<a href="mailto:'.e($supplier->email).'">'.e($supplier->email).'</a>' : '',
'assets' => $supplier->num_assets(),
'licenses' => $supplier->num_licenses(),
'actions' => $actions
);
}
$data = array('total' => $suppliersCount, 'rows' => $rows);
return $data;
}
}
File diff suppressed because it is too large Load Diff
+288
View File
@@ -0,0 +1,288 @@
<?php
namespace App\Http\Controllers;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Consumable;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use App\Models\License;
use Auth;
use Config;
use DB;
use Input;
use Lang;
use Mail;
use Redirect;
use Slack;
use Validator;
use View;
/**
* This controller handles all actions related to the ability for users
* to view their own assets in the Snipe-IT Asset Management application.
*
* @version v1.0
*/
class ViewAssetsController extends Controller
{
/**
* Redirect to the profile page.
*
* @return Redirect
*/
public function getIndex()
{
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find(Auth::user()->id);
$userlog = $user->userlog->load('assetlog', 'consumablelog', 'assetlog.model', 'licenselog', 'accessorylog', 'userlog', 'adminlog');
if (isset($user->id)) {
return View::make('account/view-assets', compact('user', 'userlog'));
} else {
// Prepare the error message
$error = trans('admin/users/message.user_not_found', compact('id'));
// Redirect to the user management page
return redirect()->route('users')->with('error', $error);
}
}
public function getRequestableIndex()
{
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assigneduser')->Hardware()->RequestableAssets()->get();
return View::make('account/requestable-assets', compact('user', 'assets'));
}
public function getRequestAsset($assetId = null)
{
$user = Auth::user();
// Check if the asset exists and is requestable
if (is_null($asset = Asset::RequestableAssets()->find($assetId))) {
// Redirect to the asset management page
return redirect()->route('requestable-assets')->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
} elseif (!Company::isCurrentUserHasAccess($asset)) {
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
} else {
$logaction = new Actionlog();
$logaction->asset_id = $data['asset_id'] = $asset->id;
$logaction->asset_type = $data['asset_type'] = 'hardware';
$logaction->created_at = $data['requested_date'] = date("Y-m-d h:i:s");
if ($user->location_id) {
$logaction->location_id = $user->location_id;
}
$logaction->user_id = $data['user_id'] = Auth::user()->id;
$log = $logaction->logaction('requested');
$data['requested_by'] = $user->fullName();
$data['asset_name'] = $asset->showAssetName();
$settings = Setting::getSettings();
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
Mail::send('emails.asset-requested', $data, function ($m) use ($user, $settings) {
$m->to(explode(',', $settings->alert_email), $settings->site_name);
$m->subject('Asset Requested');
});
}
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'REQUESTED:',
'value' => strtoupper($logaction->asset_type).' asset <'.config('app.url').'/hardware/'.$asset->id.'/view'.'|'.$asset->showAssetName().'> requested by <'.config('app.url').'/hardware/'.$asset->id.'/view'.'|'.Auth::user()->fullName().'>.'
]
]
])->send('Asset Requested');
} catch (Exception $e) {
}
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
}
}
// Get the acceptance screen
public function getAcceptAsset($logID = null)
{
if (!$findlog = DB::table('asset_logs')->where('id', '=', $logID)->first()) {
echo 'no record';
//return redirect()->to('account')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$user = Auth::user();
if ($user->id != $findlog->checkedout_to) {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
// Asset
if (($findlog->asset_id!='') && ($findlog->asset_type=='hardware')) {
$item = Asset::find($findlog->asset_id);
// software
} elseif (($findlog->asset_id!='') && ($findlog->asset_type=='software')) {
$item = License::find($findlog->asset_id);
// accessories
} elseif ($findlog->accessory_id!='') {
$item = Accessory::find($findlog->accessory_id);
// consumable
} elseif ($findlog->consumable_id!='') {
$item = Consumable::find($findlog->consumable_id);
// components
} elseif ($findlog->component_id!='') {
$item = Component::find($findlog->component_id);
}
// Check if the asset exists
if (is_null($item)) {
// Redirect to the asset management page
return redirect()->to('account')->with('error', trans('admin/hardware/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($item)) {
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
} else {
return View::make('account/accept-asset', compact('item'))->with('findlog', $findlog);
}
}
// Save the acceptance
public function postAcceptAsset($logID = null)
{
// Check if the asset exists
if (is_null($findlog = DB::table('asset_logs')->where('id', '=', $logID)->first())) {
// Redirect to the asset management page
return redirect()->to('account/view-assets')->with('error', trans('admin/hardware/message.does_not_exist'));
}
if ($findlog->accepted_id!='') {
// Redirect to the asset management page
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
}
if (!Input::has('asset_acceptance')) {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.accept_or_decline'));
}
$user = Auth::user();
if ($user->id != $findlog->checkedout_to) {
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
}
$logaction = new Actionlog();
if (Input::get('asset_acceptance')=='accepted') {
$logaction_msg = 'accepted';
$accepted="accepted";
$return_msg = trans('admin/users/message.accepted');
} else {
$logaction_msg = 'declined';
$accepted="rejected";
$return_msg = trans('admin/users/message.declined');
}
// Asset
if (($findlog->asset_id!='') && ($findlog->asset_type=='hardware')) {
$logaction->asset_id = $findlog->asset_id;
$logaction->accessory_id = null;
$logaction->asset_type = 'hardware';
if (Input::get('asset_acceptance')!='accepted') {
DB::table('assets')
->where('id', $findlog->asset_id)
->update(array('assigned_to' => null));
}
// software
} elseif (($findlog->asset_id!='') && ($findlog->asset_type=='software')) {
$logaction->asset_id = $findlog->asset_id;
$logaction->accessory_id = null;
$logaction->component_id = null;
$logaction->asset_type = 'software';
// accessories
} elseif ($findlog->accessory_id!='') {
$logaction->asset_id = null;
$logaction->component_id = null;
$logaction->accessory_id = $findlog->accessory_id;
$logaction->asset_type = 'accessory';
// accessories
} elseif ($findlog->consumable_id!='') {
$logaction->asset_id = null;
$logaction->accessory_id = null;
$logaction->component_id = null;
$logaction->consumable_id = $findlog->consumable_id;
$logaction->asset_type = 'consumable';
} elseif ($findlog->component_id!='') {
$logaction->asset_id = null;
$logaction->accessory_id = null;
$logaction->consumable_id = null;
$logaction->component_id = $findlog->component_id;
$logaction->asset_type = 'component';
}
$logaction->checkedout_to = $findlog->checkedout_to;
$logaction->note = e(Input::get('note'));
$logaction->user_id = $user->id;
$logaction->accepted_at = date("Y-m-d h:i:s");
$log = $logaction->logaction($logaction_msg);
$update_checkout = DB::table('asset_logs')
->where('id', $findlog->id)
->update(array('accepted_id' => $logaction->id));
$affected_asset=$logaction->assetlog;
$affected_asset->accepted=$accepted;
$affected_asset->save();
if ($update_checkout) {
return redirect()->to('account/view-assets')->with('success', $return_msg);
} else {
return redirect()->to('account/view-assets')->with('error', 'Something went wrong ');
}
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\FrameGuard::class,
\App\Http\Middleware\XssProtectHeader::class,
\App\Http\Middleware\NosniffGuard::class,
\App\Http\Middleware\CheckForSetup::class,
\Fideloper\Proxy\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\CheckLocale::class,
],
'api' => [
'throttle:60,1',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'authorize' => \App\Http\Middleware\CheckPermissions::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Config;
use Route;
use Schema;
use App\Models\User;
use App\Models\Setting;
class CheckForSetup
{
public function handle($request, Closure $next, $guard = null)
{
if (Setting::setupCompleted()) {
if ($request->is('setup*')) {
return redirect(config('app.url'));
} else {
return $next($request);
}
} else {
if (!$request->is('setup*')) {
return redirect(config('app.url').'/setup')->with('Request', $request);
}
return $next($request);
}
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Config;
use Route;
use Schema;
use App\Models\Setting;
class CheckLocale
{
/**
* Handle the locale for the user, default to settings otherwise
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Schema::hasTable('settings')) {
// User's preference
if (($request->user()) && ($request->user()->locale)) {
\App::setLocale($request->user()->locale);
// App setting preference
} elseif ((Setting::getSettings()) && (Setting::getSettings()->locale!='')) {
\App::setLocale(Setting::getSettings()->locale);
// Default app setting
} else {
\App::setLocale(config('app.locale'));
}
}
\App::setLocale(config('app.locale'));
return $next($request);
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Config;
use Route;
use Gate;
class CheckPermissions
{
/**
* Handle the ACLs for permissions.
*
* The $section variable is passed via the route middleware,
* 'middleware' => [authorize:superadmin']
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $section
* @return mixed
*/
public function handle($request, Closure $next, $section = null)
{
if (Gate::allows($section)) {
return $next($request);
}
return response()->view('layouts/basic', [
'content' => view('errors/403')
]);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter;
class EncryptCookies extends BaseEncrypter
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Closure;
class FrameGuard
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('X-Frame-Options', 'SAMEORIGIN', false);
return $response;
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Closure;
class NosniffGuard
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('X-Content-Type-Options', 'nosniff', false);
return $response;
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/');
}
return $next($request);
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
];
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Closure;
class XssProtectHeader
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('X-XSS-Protection', '1');
return $response;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class AssetCheckinRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
];
}
public function response(array $errors)
{
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class AssetCheckoutRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"assigned_to" => 'required',
];
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class AssetFileRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'file.*' => 'required|mimes:png,gif,jpg,jpeg,doc,docx,pdf,txt,zip,rar|max:2000'
];
}
public function response(array $errors)
{
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Models\AssetModel;
use Session;
class AssetRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
'name' => 'min:2|max:255',
'model_id' => 'required|integer',
'status_id' => 'required|integer',
'company_id' => 'integer',
'warranty_months' => 'integer|min:0|max:240',
'physical' => 'integer',
'checkout_date' => 'date',
'checkin_date' => 'date',
'supplier_id' => 'integer',
'status' => 'integer',
'asset_tag' => 'required',
];
$model = AssetModel::find($this->request->get('model_id'));
if (($model) && ($model->fieldset)) {
$rules += $model->fieldset->validation_rules();
}
return $rules;
}
public function response(array $errors)
{
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
->put('default', new \Illuminate\Support\MessageBag($errors)));
\Input::flash();
return parent::response($errors);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
protected $rules = [];
public function rules()
{
return $this->rules;
}
// public function response(array $errors)
// {
// $this->session->flash('errorMessages', $errors);
// return $this->redirector->back()->withErrors($errors)->withInput();
// }
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class SaveUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'first_name' => 'required|string|min:1',
'last_name' => 'required|string|min:1',
'username' => 'required|string|min:2|unique:users,username,NULL,deleted_at',
'email' => 'email',
'password' => 'required|min:6',
'password_confirm' => 'sometimes|required_with:password',
];
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class SetupUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'site_name' => 'required|string|min:1',
'first_name' => 'required|string|min:1',
'last_name' => 'required|string|min:1',
'username' => 'required|string|min:2|unique:users,username,NULL,deleted_at',
'email' => 'email|unique:users,email',
'password' => 'required|min:6',
'password_confirm' => 'required|min:6|same:password',
'email_domain' => 'required|min:4',
];
}
public function response(array $errors)
{
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class UpdateUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'first_name' => 'required|string|min:1',
'last_name' => 'required|string|min:1',
'email' => 'email',
'password_confirm' => 'sometimes|required_with:password',
];
}
}
+878
View File
@@ -0,0 +1,878 @@
<?php
use App\Models\Statuslabel;
use App\Models\Location;
/*
|--------------------------------------------------------------------------
| Admin API Routes
|--------------------------------------------------------------------------
*/
Route::group([ 'prefix' => 'api', 'middleware' => 'auth' ], function () {
/*---Hardware API---*/
Route::group([ 'prefix' => 'hardware','middleware' => ['web','auth','authorize:assets.view']], function () {
Route::get('list/{status?}', [ 'as' => 'api.hardware.list', 'uses' => 'AssetsController@getDatatable' ]);
Route::post('import', 'AssetsController@postAPIImportUpload');
});
/*---Status Label API---*/
Route::group([ 'prefix' => 'statuslabels' ,'middleware' => ['web','auth','authorize:admin']], function () {
Route::resource('/', 'StatuslabelsController');
Route::get('{statuslabelId}/deployable', function ($statuslabelId) {
$statuslabel = Statuslabel::find($statuslabelId);
if (( $statuslabel->deployable == '1' ) && ( $statuslabel->pending != '1' )
&& ( $statuslabel->archived != '1' )
) {
return '1';
} else {
return '0';
}
});
Route::get('list', [ 'as' => 'api.statuslabels.list', 'uses' => 'StatuslabelsController@getDatatable' ]);
Route::get('assets', [ 'as' => 'api.statuslabels.assets', 'uses' => 'StatuslabelsController@getAssetCountByStatuslabel' ]);
});
/*---Accessories API---*/
Route::group([ 'prefix' => 'accessories' ], function () {
Route::get('list', [ 'as' => 'api.accessories.list', 'uses' => 'AccessoriesController@getDatatable' ]);
Route::get(
'{accessoryID}/view',
[ 'as' => 'api.accessories.view', 'uses' => 'AccessoriesController@getDataView' ]
);
});
/*---Consumables API---*/
Route::group(array('prefix'=>'consumables'), function () {
Route::get('list', array('as'=>'api.consumables.list', 'uses'=>'ConsumablesController@getDatatable'));
Route::get('{consumableID}/view', array('as'=>'api.consumables.view', 'uses'=>'ConsumablesController@getDataView'));
});
/*---Components API---*/
Route::group(array('prefix'=>'components'), function () {
Route::get('list', array('as'=>'api.components.list', 'uses'=>'ComponentsController@getDatatable'));
Route::get('{componentID}/view', array('as'=>'api.components.view', 'uses'=>'ComponentsController@getDataView'));
});
/*---Locations API---*/
Route::group(array('prefix'=>'locations'), function () {
Route::get('list', array('as'=>'api.locations.list', 'uses'=>'LocationsController@getDatatable'));
Route::get('{locationID}/view', array('as'=>'api.locations.view', 'uses'=>'LocationsController@getDataView'));
Route::get('{locationID}/users', array('as'=>'api.locations.viewusers', 'uses'=>'LocationsController@getDataViewUsers'));
Route::get('{locationID}/assets', array('as'=>'api.locations.viewassets', 'uses'=>'LocationsController@getDataViewAssets'));
});
/*---Depreciations API---*/
Route::group(array('prefix'=>'depreciations'), function () {
Route::get('list', array('as'=>'api.depreciations.list', 'uses'=>'DepreciationsController@getDatatable'));
Route::get('{$depreciationID}/view', array('as'=>'api.depreciations.view', 'uses'=>'DepreciationsController@getDataView'));
});
/*---Manufacturers API---*/
Route::group(array('prefix'=>'manufacturers'), function () {
Route::get('list', array('as'=>'api.manufacturers.list', 'uses'=>'ManufacturersController@getDatatable'));
Route::get('{manufacturerID}/view', array('as'=>'api.manufacturers.view', 'uses'=>'ManufacturersController@getDataView'));
});
/*---Suppliers API---*/
Route::group(array('prefix'=>'suppliers'), function () {
Route::get('list', array('as'=>'api.suppliers.list', 'uses'=>'SuppliersController@getDatatable'));
});
/*---Users API---*/
Route::group([ 'prefix' => 'users' ], function () {
Route::post('/', [ 'as' => 'api.users.store', 'uses' => 'UsersController@store' ]);
Route::get('list/{status?}', [ 'as' => 'api.users.list', 'uses' => 'UsersController@getDatatable' ]);
Route::get('{userId}/assets', [ 'as' => 'api.users.assetlist', 'uses' => 'UsersController@getAssetList' ]);
Route::post('{userId}/upload', [ 'as' => 'upload/user', 'uses' => 'UsersController@postUpload' ]);
});
/*---Groups API---*/
Route::group([ 'prefix' => 'groups' ], function () {
Route::get('list', [ 'as' => 'api.groups.list', 'uses' => 'GroupsController@getDatatable' ]);
});
/*---Licenses API---*/
Route::group([ 'prefix' => 'licenses' ], function () {
Route::get('list', [ 'as' => 'api.licenses.list', 'uses' => 'LicensesController@getDatatable' ]);
});
/*---Locations API---*/
Route::group([ 'prefix' => 'locations' ], function () {
Route::resource('/', 'LocationsController');
Route::get('{locationID}/check', function ($locationID) {
$location = Location::find($locationID);
return $location;
});
});
/*---Improvements API---*/
Route::group([ 'prefix' => 'asset_maintenances' ], function () {
Route::get(
'list',
[ 'as' => 'api.asset_maintenances.list', 'uses' => 'AssetMaintenancesController@getDatatable' ]
);
});
/*---Models API---*/
Route::group([ 'prefix' => 'models' ], function () {
Route::resource('/', 'AssetModelsController');
Route::get('list/{status?}', [ 'as' => 'api.models.list', 'uses' => 'AssetModelsController@getDatatable' ]);
Route::get('{modelID}/view', [ 'as' => 'api.models.view', 'uses' => 'AssetModelsController@getDataView' ]);
});
/*--- Categories API---*/
Route::group([ 'prefix' => 'categories' ], function () {
Route::get('list', [ 'as' => 'api.categories.list', 'uses' => 'CategoriesController@getDatatable' ]);
Route::get(
'{categoryID}/asset/view',
[ 'as' => 'api.categories.asset.view', 'uses' => 'CategoriesController@getDataViewAssets' ]
);
Route::get(
'{categoryID}/accessory/view',
[ 'as' => 'api.categories.accessory.view', 'uses' => 'CategoriesController@getDataViewAccessories' ]
);
Route::get(
'{categoryID}/consumable/view',
[ 'as' => 'api.categories.consumable.view', 'uses' => 'CategoriesController@getDataViewConsumables' ]
);
Route::get(
'{categoryID}/component/view',
[ 'as' => 'api.categories.component.view', 'uses' => 'CategoriesController@getDataViewComponent' ]
);
});
/*-- Suppliers API (mostly for creating new ones in-line while creating an asset) --*/
Route::group([ 'prefix' => 'suppliers' ], function () {
Route::resource('/', 'SuppliersController');
});
/*-- Custom fields API --*/
Route::group([ 'prefix' => 'custom_fields' ], function () {
Route::post(
'{fieldsetID}/order',
[ 'as' => 'api.customfields.order', 'uses' => 'CustomFieldsController@postReorder' ]
);
});
});
/*
|--------------------------------------------------------------------------
| Asset Routes
|--------------------------------------------------------------------------
|
| Register all the asset routes.
|
*/
Route::group(
[ 'prefix' => 'hardware',
'middleware' => ['web',
'auth',
'authorize:assets.view']],
function () {
Route::get('create/{model?}', [
'as' => 'create/hardware',
'uses' => 'AssetsController@getCreate'
]);
Route::post('create', [
'as' => 'savenew/hardware',
'uses' => 'AssetsController@postCreate'
]);
Route::get('{assetId}/edit', [
'as' => 'update/hardware',
'uses' => 'AssetsController@getEdit'
]);
Route::get('/bytag', [
'as' => 'findbytag/hardware',
'uses' => 'AssetsController@getAssetByTag'
]);
Route::get('{assetId}/clone', [ 'as' => 'clone/hardware', 'uses' => 'AssetsController@getClone' ]);
Route::post('{assetId}/clone', 'AssetsController@postCreate');
Route::get('{assetId}/delete', [ 'as' => 'delete/hardware', 'uses' => 'AssetsController@getDelete' ]);
Route::get(
'{assetId}/checkout',
[ 'as' => 'checkout/hardware', 'uses' => 'AssetsController@getCheckout' ]
);
Route::post('{assetId}/checkout', 'AssetsController@postCheckout');
Route::get(
'{assetId}/checkin/{backto?}',
[ 'as' => 'checkin/hardware', 'uses' => 'AssetsController@getCheckin' ]
);
Route::post('{assetId}/checkin/{backto?}', 'AssetsController@postCheckin');
Route::get('{assetId}/view', [ 'as' => 'view/hardware', 'uses' => 'AssetsController@getView' ]);
Route::get('{assetId}/qr-view', [ 'as' => 'qr-view/hardware', 'uses' => 'AssetsController@getView' ]);
Route::get('{assetId}/qr_code', [ 'as' => 'qr_code/hardware', 'uses' => 'AssetsController@getQrCode' ]);
Route::get('{assetId}/barcode', [ 'as' => 'barcode/hardware', 'uses' => 'AssetsController@getBarCode' ]);
Route::get('{assetId}/restore', [ 'as' => 'restore/hardware', 'uses' => 'AssetsController@getRestore' ]);
Route::post('{assetId}/upload', [ 'as' => 'upload/asset', 'uses' => 'AssetsController@postUpload' ]);
Route::get(
'{assetId}/deletefile/{fileId}',
[ 'as' => 'delete/assetfile', 'uses' => 'AssetsController@getDeleteFile' ]
);
Route::get(
'{assetId}/showfile/{fileId}',
[ 'as' => 'show/assetfile', 'uses' => 'AssetsController@displayFile' ]
);
Route::get(
'import/delete-import/{filename}',
[ 'as' => 'assets/import/delete-file', 'uses' => 'AssetsController@getDeleteImportFile' ]
);
Route::get(
'import/process/{filename}',
[ 'as' => 'assets/import/process-file', 'uses' => 'AssetsController@getProcessImportFile' ]
);
Route::get(
'import',
[ 'as' => 'assets/import', 'uses' => 'AssetsController@getImportUpload' ]
);
Route::post('{assetId}/edit', 'AssetsController@postEdit');
Route::post(
'bulkedit',
[
'as' => 'hardware/bulkedit',
'uses' => 'AssetsController@postBulkEdit'
]
);
Route::post(
'bulkdelete',
[
'as' => 'hardware/bulkdelete',
'uses' => 'AssetsController@postBulkDelete'
]
);
Route::post(
'bulksave',
[
'as' => 'hardware/bulksave',
'uses' => 'AssetsController@postBulkSave'
]
);
# Asset Model Management
Route::group([ 'prefix' => 'models', 'middleware' => 'auth' ], function () {
Route::get('/', [ 'as' => 'models', 'uses' => 'AssetModelsController@getIndex' ]);
Route::get('create', [ 'as' => 'create/model', 'uses' => 'AssetModelsController@getCreate' ]);
Route::post('create', 'AssetModelsController@postCreate');
Route::get('{modelId}/edit', [ 'as' => 'update/model', 'uses' => 'AssetModelsController@getEdit' ]);
Route::post('{modelId}/edit', 'AssetModelsController@postEdit');
Route::get('{modelId}/clone', [ 'as' => 'clone/model', 'uses' => 'AssetModelsController@getClone' ]);
Route::post('{modelId}/clone', 'AssetModelsController@postCreate');
Route::get('{modelId}/delete', [ 'as' => 'delete/model', 'uses' => 'AssetModelsController@getDelete' ]);
Route::get('{modelId}/view', [ 'as' => 'view/model', 'uses' => 'AssetModelsController@getView' ]);
Route::get('{modelID}/restore', [ 'as' => 'restore/model', 'uses' => 'AssetModelsController@getRestore' ]);
Route::get('{modelId}/custom_fields', ['as' => 'custom_fields/model','uses' => 'AssetModelsController@getCustomFields']);
});
Route::get('/', [
'as' => 'hardware',
'uses' => 'AssetsController@getIndex'
]);
}
);
/*
|--------------------------------------------------------------------------
| Admin Routes
|--------------------------------------------------------------------------
|
| Register all the admin routes.
|
*/
Route::group([ 'prefix' => 'admin','middleware' => ['web','auth']], function () {
# Licenses
Route::group([ 'prefix' => 'licenses', 'middleware'=>'authorize:licenses.view' ], function () {
Route::get('create', [ 'as' => 'create/licenses', 'uses' => 'LicensesController@getCreate' ]);
Route::post('create', 'LicensesController@postCreate');
Route::get('{licenseId}/edit', [ 'as' => 'update/license', 'uses' => 'LicensesController@getEdit' ]);
Route::post('{licenseId}/edit', 'LicensesController@postEdit');
Route::get('{licenseId}/clone', [ 'as' => 'clone/license', 'uses' => 'LicensesController@getClone' ]);
Route::post('{licenseId}/clone', 'LicensesController@postCreate');
Route::get('{licenseId}/delete', [ 'as' => 'delete/license', 'uses' => 'LicensesController@getDelete' ]);
Route::get(
'{licenseId}/freecheckout',
[ 'as' => 'freecheckout/license', 'uses' => 'LicensesController@getFreeLicense' ]
);
Route::get(
'{licenseId}/checkout',
[ 'as' => 'checkout/license', 'uses' => 'LicensesController@getCheckout' ]
);
Route::post('{licenseId}/checkout', 'LicensesController@postCheckout');
Route::get(
'{licenseId}/checkin/{backto?}',
[ 'as' => 'checkin/license', 'uses' => 'LicensesController@getCheckin' ]
);
Route::post('{licenseId}/checkin/{backto?}', 'LicensesController@postCheckin');
Route::get('{licenseId}/view', [ 'as' => 'view/license', 'uses' => 'LicensesController@getView' ]);
Route::post(
'{licenseId}/upload',
[ 'as' => 'upload/license', 'uses' => 'LicensesController@postUpload' ]
);
Route::get(
'{licenseId}/deletefile/{fileId}',
[ 'as' => 'delete/licensefile', 'uses' => 'LicensesController@getDeleteFile' ]
);
Route::get(
'{licenseId}/showfile/{fileId}',
[ 'as' => 'show/licensefile', 'uses' => 'LicensesController@displayFile' ]
);
Route::get('/', [ 'as' => 'licenses', 'uses' => 'LicensesController@getIndex' ]);
});
# Asset Maintenances
Route::group([ 'prefix' => 'asset_maintenances', 'middleware'=>'authorize:assets.view' ], function () {
Route::get(
'create/{assetId?}',
[ 'as' => 'create/asset_maintenances', 'uses' => 'AssetMaintenancesController@getCreate' ]
);
Route::post('create/{assetId?}', 'AssetMaintenancesController@postCreate');
Route::get('/', [ 'as' => 'asset_maintenances', 'uses' => 'AssetMaintenancesController@getIndex' ]);
Route::get(
'{assetMaintenanceId}/edit',
[ 'as' => 'update/asset_maintenance', 'uses' => 'AssetMaintenancesController@getEdit' ]
);
Route::post('{assetMaintenanceId}/edit', 'AssetMaintenancesController@postEdit');
Route::get(
'{assetMaintenanceId}/delete',
[ 'as' => 'delete/asset_maintenance', 'uses' => 'AssetMaintenancesController@getDelete' ]
);
Route::get(
'{assetMaintenanceId}/view',
[ 'as' => 'view/asset_maintenance', 'uses' => 'AssetMaintenancesController@getView' ]
);
});
# Accessories
Route::group([ 'prefix' => 'accessories', 'middleware'=>'authorize:accessories.view' ], function () {
Route::get('create', [ 'as' => 'create/accessory', 'uses' => 'AccessoriesController@getCreate' ]);
Route::post('create', 'AccessoriesController@postCreate');
Route::get(
'{accessoryID}/edit',
[ 'as' => 'update/accessory', 'uses' => 'AccessoriesController@getEdit' ]
);
Route::post('{accessoryID}/edit', 'AccessoriesController@postEdit');
Route::get(
'{accessoryID}/delete',
[ 'as' => 'delete/accessory', 'uses' => 'AccessoriesController@getDelete' ]
);
Route::get('{accessoryID}/view', [ 'as' => 'view/accessory', 'uses' => 'AccessoriesController@getView' ]);
Route::get(
'{accessoryID}/checkout',
[ 'as' => 'checkout/accessory', 'uses' => 'AccessoriesController@getCheckout' ]
);
Route::post('{accessoryID}/checkout', 'AccessoriesController@postCheckout');
Route::get(
'{accessoryID}/checkin/{backto?}',
[ 'as' => 'checkin/accessory', 'uses' => 'AccessoriesController@getCheckin' ]
);
Route::post('{accessoryID}/checkin/{backto?}', 'AccessoriesController@postCheckin');
Route::get('/', [ 'as' => 'accessories', 'uses' => 'AccessoriesController@getIndex' ]);
});
# Consumables
Route::group([ 'prefix' => 'consumables', 'middleware'=>'authorize:consumables.view' ], function () {
Route::get('create', [ 'as' => 'create/consumable', 'uses' => 'ConsumablesController@getCreate' ]);
Route::post('create', 'ConsumablesController@postCreate');
Route::get(
'{consumableID}/edit',
[ 'as' => 'update/consumable', 'uses' => 'ConsumablesController@getEdit' ]
);
Route::post('{consumableID}/edit', 'ConsumablesController@postEdit');
Route::get(
'{consumableID}/delete',
[ 'as' => 'delete/consumable', 'uses' => 'ConsumablesController@getDelete' ]
);
Route::get(
'{consumableID}/view',
[ 'as' => 'view/consumable', 'uses' => 'ConsumablesController@getView' ]
);
Route::get(
'{consumableID}/checkout',
[ 'as' => 'checkout/consumable', 'uses' => 'ConsumablesController@getCheckout' ]
);
Route::post('{consumableID}/checkout', 'ConsumablesController@postCheckout');
Route::get('/', [ 'as' => 'consumables', 'uses' => 'ConsumablesController@getIndex' ]);
});
# Components
Route::group([ 'prefix' => 'components', 'middleware'=>'authorize:components.view' ], function () {
Route::get('create', [ 'as' => 'create/component', 'uses' => 'ComponentsController@getCreate' ]);
Route::post('create', 'ComponentsController@postCreate');
Route::get(
'{componentID}/edit',
[ 'as' => 'update/component', 'uses' => 'ComponentsController@getEdit' ]
);
Route::post('{componentID}/edit', 'ComponentsController@postEdit');
Route::get(
'{componentID}/delete',
[ 'as' => 'delete/component', 'uses' => 'ComponentsController@getDelete' ]
);
Route::get(
'{componentID}/view',
[ 'as' => 'view/component', 'uses' => 'ComponentsController@getView' ]
);
Route::get(
'{componentID}/checkout',
[ 'as' => 'checkout/component', 'uses' => 'ComponentsController@getCheckout' ]
);
Route::post('{componentID}/checkout', 'ComponentsController@postCheckout');
Route::post('bulk', [ 'as' => 'component/bulk-form', 'uses' => 'ComponentsController@postBulk' ]);
Route::post('bulksave', [ 'as' => 'component/bulk-save', 'uses' => 'ComponentsController@postBulkSave' ]);
Route::get('/', [ 'as' => 'components', 'uses' => 'ComponentsController@getIndex' ]);
});
# Admin Settings Routes (for categories, maufactureres, etc)
Route::group([ 'prefix' => 'settings', 'middleware'=>'authorize:superuser'], function () {
# Settings
Route::group([ 'prefix' => 'app' ], function () {
Route::post('purge', ['as' => 'purge', 'uses' => 'SettingsController@postPurge']);
Route::get('edit', [ 'as' => 'edit/settings', 'uses' => 'SettingsController@getEdit' ]);
Route::post('edit', 'SettingsController@postEdit');
Route::get('ldaptest', [
'as' => 'settings/ldaptest',
'uses' => 'SettingsController@getLdapTest'
]);
Route::get('/', [ 'as' => 'app', 'uses' => 'SettingsController@getIndex' ]);
});
# Settings
Route::group([ 'prefix' => 'backups', 'middleware' => 'auth' ], function () {
Route::get('download/{filename}', [
'as' => 'settings/download-file',
'uses' => 'SettingsController@downloadFile' ]);
Route::get('delete/{filename}', [
'as' => 'settings/delete-file',
'uses' => 'SettingsController@deleteFile' ]);
Route::post('/', [
'as' => 'settings/backups',
'uses' => 'SettingsController@postBackups'
]);
Route::get('/', [ 'as' => 'settings/backups', 'uses' => 'SettingsController@getBackups' ]);
});
# Companies
Route::group([ 'prefix' => 'companies' ], function () {
Route::get('{companyId}/edit', ['as' => 'update/company', 'uses' => 'CompaniesController@getEdit']);
Route::get('create', ['as' => 'create/company', 'uses' => 'CompaniesController@getCreate']);
Route::get('/', ['as' => 'companies', 'uses' => 'CompaniesController@getIndex']);
Route::post('{companyId}/delete', ['as' => 'delete/company', 'uses' => 'CompaniesController@postDelete']);
Route::post('{companyId}/edit', 'CompaniesController@postEdit');
Route::post('create', 'CompaniesController@postCreate');
});
# Manufacturers
Route::group([ 'prefix' => 'manufacturers' ], function () {
Route::get('/', [ 'as' => 'manufacturers', 'uses' => 'ManufacturersController@getIndex' ]);
Route::get(
'create',
[ 'as' => 'create/manufacturer', 'uses' => 'ManufacturersController@getCreate' ]
);
Route::post('create', 'ManufacturersController@postCreate');
Route::get(
'{manufacturerId}/edit',
[ 'as' => 'update/manufacturer', 'uses' => 'ManufacturersController@getEdit' ]
);
Route::post('{manufacturerId}/edit', 'ManufacturersController@postEdit');
Route::get(
'{manufacturerId}/delete',
[ 'as' => 'delete/manufacturer', 'uses' => 'ManufacturersController@getDelete' ]
);
Route::get(
'{manufacturerId}/view',
[ 'as' => 'view/manufacturer', 'uses' => 'ManufacturersController@getView' ]
);
});
# Suppliers
Route::group([ 'prefix' => 'suppliers' ], function () {
Route::get('/', [ 'as' => 'suppliers', 'uses' => 'SuppliersController@getIndex' ]);
Route::get('create', [ 'as' => 'create/supplier', 'uses' => 'SuppliersController@getCreate' ]);
Route::post('create', 'SuppliersController@postCreate');
Route::get(
'{supplierId}/edit',
[ 'as' => 'update/supplier', 'uses' => 'SuppliersController@getEdit' ]
);
Route::post('{supplierId}/edit', 'SuppliersController@postEdit');
Route::get(
'{supplierId}/delete',
[ 'as' => 'delete/supplier', 'uses' => 'SuppliersController@getDelete' ]
);
Route::get('{supplierId}/view', [ 'as' => 'view/supplier', 'uses' => 'SuppliersController@getView' ]);
});
# Categories
Route::group([ 'prefix' => 'categories' ], function () {
Route::get('create', [ 'as' => 'create/category', 'uses' => 'CategoriesController@getCreate' ]);
Route::post('create', 'CategoriesController@postCreate');
Route::get(
'{categoryId}/edit',
[ 'as' => 'update/category', 'uses' => 'CategoriesController@getEdit' ]
);
Route::post('{categoryId}/edit', 'CategoriesController@postEdit');
Route::get(
'{categoryId}/delete',
[ 'as' => 'delete/category', 'uses' => 'CategoriesController@getDelete' ]
);
Route::get(
'{categoryId}/view',
[ 'as' => 'view/category', 'uses' => 'CategoriesController@getView' ]
);
Route::get('/', [ 'as' => 'categories', 'uses' => 'CategoriesController@getIndex' ]);
});
# Depreciations
Route::group([ 'prefix' => 'depreciations' ], function () {
Route::get('/', [ 'as' => 'depreciations', 'uses' => 'DepreciationsController@getIndex' ]);
Route::get(
'create',
[ 'as' => 'create/depreciations', 'uses' => 'DepreciationsController@getCreate' ]
);
Route::post('create', 'DepreciationsController@postCreate');
Route::get(
'{depreciationId}/edit',
[ 'as' => 'update/depreciations', 'uses' => 'DepreciationsController@getEdit' ]
);
Route::post('{depreciationId}/edit', 'DepreciationsController@postEdit');
Route::get(
'{depreciationId}/delete',
[ 'as' => 'delete/depreciations', 'uses' => 'DepreciationsController@getDelete' ]
);
});
# Locations
Route::group([ 'prefix' => 'locations' ], function () {
Route::get('/', [ 'as' => 'locations', 'uses' => 'LocationsController@getIndex' ]);
Route::get('create', [ 'as' => 'create/location', 'uses' => 'LocationsController@getCreate' ]);
Route::post('create', 'LocationsController@postCreate');
Route::get(
'{locationId}/edit',
[ 'as' => 'update/location', 'uses' => 'LocationsController@getEdit' ]
);
Route::post('{locationId}/edit', 'LocationsController@postEdit');
Route::get('{locationId}/view', 'LocationsController@getView');
Route::get(
'{locationId}/delete',
[ 'as' => 'delete/location', 'uses' => 'LocationsController@getDelete' ]
);
});
# Status Labels
Route::group([ 'prefix' => 'statuslabels' ], function () {
Route::get('/', [ 'as' => 'statuslabels', 'uses' => 'StatuslabelsController@getIndex' ]);
Route::get('create', [ 'as' => 'create/statuslabel', 'uses' => 'StatuslabelsController@getCreate' ]);
Route::post('create', 'StatuslabelsController@postCreate');
Route::get(
'{statuslabelId}/edit',
[ 'as' => 'update/statuslabel', 'uses' => 'StatuslabelsController@getEdit' ]
);
Route::post('{statuslabelId}/edit', 'StatuslabelsController@postEdit');
Route::get(
'{statuslabelId}/delete',
[ 'as' => 'delete/statuslabel', 'uses' => 'StatuslabelsController@getDelete' ]
);
});
});
# Custom fields support
Route::get('custom_fields/create-field', ['uses' =>'CustomFieldsController@createField','as' => 'admin.custom_fields.create-field']);
Route::post('custom_fields/create-field', ['uses' => 'CustomFieldsController@storeField','as' => 'admin.custom_fields.store-field']);
Route::post('custom_fields/{id}/associate', ['uses' => 'CustomFieldsController@associate','as' => 'admin.custom_fields.associate']);
Route::match(['DELETE'], 'custom_fields/delete-field/{id}', ['uses' => 'CustomFieldsController@deleteField','as' => 'admin.custom_fields.delete-field']);
Route::resource('custom_fields', 'CustomFieldsController');
# User Management
Route::group([ 'prefix' => 'users', 'middleware' => ['web','auth','authorize:users.view']], function () {
Route::get('ldap', ['as' => 'ldap/user', 'uses' => 'UsersController@getLDAP' ]);
Route::post('ldap', 'UsersController@postLDAP');
Route::get('create', [ 'as' => 'create/user', 'uses' => 'UsersController@getCreate' ]);
Route::post('create', 'UsersController@postCreate');
Route::get('import', [ 'as' => 'import/user', 'uses' => 'UsersController@getImport' ]);
Route::post('import', 'UsersController@postImport');
Route::get('{userId}/edit', [ 'as' => 'update/user', 'uses' => 'UsersController@getEdit' ]);
Route::post('{userId}/edit', 'UsersController@postEdit');
Route::get('{userId}/clone', [ 'as' => 'clone/user', 'uses' => 'UsersController@getClone' ]);
Route::post('{userId}/clone', 'UsersController@postCreate');
Route::get('{userId}/delete', [ 'as' => 'delete/user', 'uses' => 'UsersController@getDelete' ]);
Route::get('{userId}/restore', [ 'as' => 'restore/user', 'uses' => 'UsersController@getRestore' ]);
Route::get('{userId}/view', [ 'as' => 'view/user', 'uses' => 'UsersController@getView' ]);
Route::get('{userId}/unsuspend', [ 'as' => 'unsuspend/user', 'uses' => 'UsersController@getUnsuspend' ]);
Route::get(
'{userId}/deletefile/{fileId}',
[ 'as' => 'delete/userfile', 'uses' => 'UsersController@getDeleteFile' ]
);
Route::get(
'{userId}/showfile/{fileId}',
[ 'as' => 'show/userfile', 'uses' => 'UsersController@displayFile' ]
);
Route::post(
'bulkedit',
[
'as' => 'users/bulkedit',
'uses' => 'UsersController@postBulkEdit'
]
);
Route::post(
'bulksave',
[
'as' => 'users/bulksave',
'uses' => 'UsersController@postBulkSave'
]
);
Route::get('/', [ 'as' => 'users', 'uses' => 'UsersController@getIndex' ]);
});
# Group Management
Route::group([ 'prefix' => 'groups', 'middleware' => ['web','auth','authorize:superadmin'] ], function () {
Route::get('/', [ 'as' => 'groups', 'uses' => 'GroupsController@getIndex' ]);
Route::get('create', [ 'as' => 'create/group', 'uses' => 'GroupsController@getCreate' ]);
Route::post('create', 'GroupsController@postCreate');
Route::get('{groupId}/edit', [ 'as' => 'update/group', 'uses' => 'GroupsController@getEdit' ]);
Route::post('{groupId}/edit', 'GroupsController@postEdit');
Route::get('{groupId}/delete', [ 'as' => 'delete/group', 'uses' => 'GroupsController@getDelete' ]);
Route::get('{groupId}/restore', [ 'as' => 'restore/group', 'uses' => 'GroupsController@getRestore' ]);
Route::get('{groupId}/view', [ 'as' => 'view/group', 'uses' => 'GroupsController@getView' ]);
});
# Dashboard
Route::get('/', [ 'as' => 'admin', 'uses' => 'DashboardController@getIndex' ]);
});
/*
|--------------------------------------------------------------------------
| Account Routes
|--------------------------------------------------------------------------
|
|
|
*/
Route::group([ 'prefix' => 'account', 'middleware' => ['web', 'auth']], function () {
# Profile
Route::get('profile', [ 'as' => 'profile', 'uses' => 'ProfileController@getIndex' ]);
Route::post('profile', 'ProfileController@postIndex');
# View Assets
Route::get('view-assets', [ 'as' => 'view-assets', 'uses' => 'ViewAssetsController@getIndex' ]);
# Accept Asset
Route::get(
'accept-asset/{logID}',
[ 'as' => 'account/accept-assets', 'uses' => 'ViewAssetsController@getAcceptAsset' ]
);
Route::post(
'accept-asset/{logID}',
[ 'as' => 'account/asset-accepted', 'uses' => 'ViewAssetsController@postAcceptAsset' ]
);
# Profile
Route::get(
'requestable-assets',
[ 'as' => 'requestable-assets', 'uses' => 'ViewAssetsController@getRequestableIndex' ]
);
Route::get(
'request-asset/{assetId}',
[ 'as' => 'account/request-asset', 'uses' => 'ViewAssetsController@getRequestAsset' ]
);
# Account Dashboard
Route::get('/', [ 'as' => 'account', 'uses' => 'ViewAssetsController@getIndex' ]);
});
Route::group(['middleware' => ['web','auth','authorize:reports.view']], function () {
Route::get(
'reports/depreciation',
[ 'as' => 'reports/depreciation', 'uses' => 'ReportsController@getDeprecationReport' ]
);
Route::get(
'reports/export/depreciation',
[ 'as' => 'reports/export/depreciation', 'uses' => 'ReportsController@exportDeprecationReport' ]
);
Route::get(
'reports/asset_maintenances',
[ 'as' => 'reports/asset_maintenances', 'uses' => 'ReportsController@getAssetMaintenancesReport' ]
);
Route::get(
'reports/export/asset_maintenances',
[
'as' => 'reports/export/asset_maintenances',
'uses' => 'ReportsController@exportAssetMaintenancesReport'
]
);
Route::get(
'reports/licenses',
[ 'as' => 'reports/licenses', 'uses' => 'ReportsController@getLicenseReport' ]
);
Route::get(
'reports/export/licenses',
[ 'as' => 'reports/export/licenses', 'uses' => 'ReportsController@exportLicenseReport' ]
);
Route::get('reports/assets', [ 'as' => 'reports/assets', 'uses' => 'ReportsController@getAssetsReport' ]);
Route::get(
'reports/export/assets',
[ 'as' => 'reports/export/assets', 'uses' => 'ReportsController@exportAssetReport' ]
);
Route::get('reports/accessories', [ 'as' => 'reports/accessories', 'uses' => 'ReportsController@getAccessoryReport' ]);
Route::get(
'reports/export/accessories',
[ 'as' => 'reports/export/accessories', 'uses' => 'ReportsController@exportAccessoryReport' ]
);
Route::get('reports/custom', [ 'as' => 'reports/custom', 'uses' => 'ReportsController@getCustomReport' ]);
Route::post('reports/custom', 'ReportsController@postCustom');
Route::get(
'reports/activity',
[ 'as' => 'reports/activity', 'uses' => 'ReportsController@getActivityReport' ]
);
Route::get(
'reports/unaccepted_assets',
[ 'as' => 'reports/unaccepted_assets', 'uses' => 'ReportsController@getAssetAcceptanceReport' ]
);
Route::get(
'reports/export/unaccepted_assets',
[ 'as' => 'reports/export/unaccepted_assets', 'uses' => 'ReportsController@exportAssetAcceptanceReport' ]
);
});
/*
|--------------------------------------------------------------------------
| Setup Routes
|--------------------------------------------------------------------------
|
|
|
*/
Route::group([ 'prefix' => 'setup', 'middleware' => 'web'], function () {
Route::get(
'user',
[
'as' => 'setup.user',
'uses' => 'SettingsController@getSetupUser' ]
);
Route::post(
'user',
[
'as' => 'setup.user.save',
'uses' => 'SettingsController@postSaveFirstAdmin' ]
);
Route::get(
'migrate',
[
'as' => 'setup.migrate',
'uses' => 'SettingsController@getSetupMigrate' ]
);
Route::get(
'done',
[
'as' => 'setup.done',
'uses' => 'SettingsController@getSetupDone' ]
);
Route::get(
'mailtest',
[
'as' => 'setup.mailtest',
'uses' => 'SettingsController@ajaxTestEmail' ]
);
Route::get(
'/',
[
'as' => 'setup',
'uses' => 'SettingsController@getSetupIndex' ]
);
});
Route::get(
'/',
[
'as' => 'home',
'middleware' => ['web', 'auth'],
'uses' => 'DashboardController@getIndex' ]
);
Route::group(['middleware' => 'web'], function () {
Route::auth();
});
Route::get('home', function () {
return redirect('/');
});
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
}
View File
+193
View File
@@ -0,0 +1,193 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Model for Accessories.
*
* @version v1.0
*/
class Accessory extends Model
{
use SoftDeletes;
use CompanyableTrait;
protected $dates = ['deleted_at'];
protected $table = 'accessories';
/**
* Accessory validation rules
*/
public $rules = array(
'name' => 'required|min:3|max:255',
'qty' => 'required|integer|min:1',
'category_id' => 'required|integer',
'company_id' => 'integer',
'min_amt' => 'integer|min:1',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','qty','category_id'];
public function company()
{
return $this->belongsTo('\App\Models\Company', 'company_id');
}
public function location()
{
return $this->belongsTo('\App\Models\Location', 'location_id');
}
public function category()
{
return $this->belongsTo('\App\Models\Category', 'category_id')->where('category_type', '=', 'accessory');
}
/**
* Get action logs for this accessory
*/
public function assetlog()
{
return $this->hasMany('\App\Models\Actionlog', 'accessory_id')->where('asset_type', '=', 'accessory')->orderBy('created_at', 'desc')->withTrashed();
}
public function users()
{
return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id')->withTrashed();
}
public function hasUsers()
{
return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->count();
}
public function checkin_email()
{
return $this->category->checkin_email;
}
public function requireAcceptance()
{
return $this->category->require_acceptance;
}
public function getEula()
{
$Parsedown = new \Parsedown();
if ($this->category->eula_text) {
return $Parsedown->text(e($this->category->eula_text));
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula=='1')) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
}
}
public function numRemaining()
{
$checkedout = $this->users->count();
$total = $this->qty;
$remaining = $total - $checkedout;
return $remaining;
}
/**
* 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)
{
$search = explode('+', $search);
return $query->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('categories.name', 'LIKE', '%'.$search.'%');
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assetlog', function ($query) use ($search) {
$query->where('action_type', '=', 'checkout')
->where('created_at', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('location', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere('accessories.name', 'LIKE', '%'.$search.'%')
->orWhere('accessories.order_number', 'LIKE', '%'.$search.'%')
->orWhere('accessories.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('accessories.purchase_date', 'LIKE', '%'.$search.'%');
}
});
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCompany($query, $order)
{
return $query->leftJoin('companies', 'accessories.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCategory($query, $order)
{
return $query->leftJoin('categories', 'accessories.category_id', '=', 'categories.id')->orderBy('categories.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderLocation($query, $order)
{
return $query->leftJoin('locations', 'consumables.location_id', '=', 'locations.id')->orderBy('locations.name', $order);
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Model for the Actionlog (the table that keeps a historical log of
* checkouts, checkins, and updates).
*
* @version v1.0
*/
class Actionlog extends Model implements ICompanyableChild
{
use SoftDeletes;
use CompanyableChildTrait;
protected $dates = [ 'deleted_at' ];
protected $table = 'asset_logs';
public $timestamps = true;
protected $fillable = [ 'created_at', 'asset_type' ];
public function getCompanyableParents()
{
return [ 'accessorylog', 'assetlog', 'licenselog', 'consumablelog' ];
}
public function assetlog()
{
return $this->belongsTo('\App\Models\Asset', 'asset_id')
->withTrashed();
}
public function uploads()
{
return $this->belongsTo('\App\Models\Asset', 'asset_id')
->where('action_type', '=', 'uploaded')
->withTrashed();
}
public function licenselog()
{
return $this->belongsTo('\App\Models\License', 'asset_id')
->withTrashed();
}
public function componentlog()
{
return $this->belongsTo('\App\Models\Component', 'component_id')
->withTrashed();
}
public function accessorylog()
{
return $this->belongsTo('\App\Models\Accessory', 'accessory_id')
->withTrashed();
}
public function consumablelog()
{
return $this->belongsTo('\App\Models\Consumable', 'consumable_id')
->withTrashed();
}
public function adminlog()
{
return $this->belongsTo('\App\Models\User', 'user_id')
->withTrashed();
}
public function userlog()
{
return $this->belongsTo('\App\Models\User', 'checkedout_to')
->withTrashed();
}
public function childlogs()
{
return $this->hasMany('\App\Models\ActionLog', 'thread_id');
}
public function parentlog()
{
return $this->belongsTo('\App\Models\ActionLog', 'thread_id');
}
/**
* Check if the file exists, and if it does, force a download
**/
public function get_src($type = 'assets')
{
$file = config('app.private_uploads') . '/' . $type . '/' . $this->filename;
return $file;
}
/**
* Get the parent category name
*/
public function logaction($actiontype)
{
$this->action_type = $actiontype;
if ($this->save()) {
return true;
} else {
return false;
}
}
/**
* getListingOfActionLogsChronologicalOrder
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function getListingOfActionLogsChronologicalOrder()
{
return DB::table('asset_logs')
->select('*')
->where('action_type', '!=', 'uploaded')
->orderBy('asset_id', 'asc')
->orderBy('created_at', 'asc')
->get();
}
/**
* getLatestCheckoutActionForAssets
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function getLatestCheckoutActionForAssets()
{
return DB::table('asset_logs')
->select(DB::raw('asset_id, MAX(created_at) as last_created'))
->where('action_type', '=', 'checkout')
->groupBy('asset_id')
->get();
}
/**
* scopeCheckoutWithoutAcceptance
*
* @param $query
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function scopeCheckoutWithoutAcceptance($query)
{
return $query->where('action_type', '=', 'checkout')
->where('accepted_id', '=', null);
}
}
+897
View File
@@ -0,0 +1,897 @@
<?php
namespace App\Models;
use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Location;
use Config;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Log;
use Parsedown;
use Watson\Validating\ValidatingTrait;
use DateTime;
use App\Models\Setting;
use App\Helpers\Helper;
use Auth;
/**
* Model for Assets.
*
* @version v1.0
*/
class Asset extends Depreciable
{
use SoftDeletes;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'assets';
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
protected $rules = [
'name' => 'min:2|max:255',
'model_id' => 'required|integer',
'status_id' => 'required|integer',
'company_id' => 'integer',
'warranty_months' => 'integer|min:0|max:240',
'physical' => 'integer',
'checkout_date' => 'date|max:10|min:10',
'checkin_date' => 'date|max:10|min:10',
'supplier_id' => 'integer',
'asset_tag' => 'required|min:1|max:255|unique:assets,asset_tag,NULL,deleted_at',
'status' => 'integer',
];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','model_id','status_id','asset_tag'];
public function company()
{
return $this->belongsTo('\App\Models\Company', 'company_id');
}
/**
* Checkout asset
*/
public function checkOutToUser($user, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
{
if ($expected_checkin) {
$this->expected_checkin = $expected_checkin ;
}
$this->last_checkout = $checkout_at;
$this->assigneduser()->associate($user);
$this->name = $name;
$settings = Setting::getSettings();
if ($this->requireAcceptance()) {
$this->accepted="pending";
}
if (!$user) {
return false;
}
if ($this->save()) {
// $action, $admin, $user, $expected_checkin = null, $note = null, $checkout_at = null
$log = $this->createLogRecord('checkout', $this, $admin, $user, $expected_checkin, $note, $checkout_at);
if ((($this->requireAcceptance()=='1') || ($this->getEula())) && ($user->email!='')) {
$this->checkOutNotifyMail($log->id, $user, $checkout_at, $expected_checkin, $note);
}
if ($settings->slack_endpoint) {
$this->checkOutNotifySlack($settings, $admin, $note);
}
return true;
}
return false;
}
public function checkOutNotifyMail($log_id, $user, $checkout_at, $expected_checkin, $note)
{
$data['log_id'] = $log_id;
$data['eula'] = $this->getEula();
$data['first_name'] = $user->first_name;
$data['item_name'] = $this->showAssetName();
$data['checkout_date'] = $checkout_at;
$data['expected_checkin'] = $expected_checkin;
$data['item_tag'] = $this->asset_tag;
$data['note'] = $note;
$data['item_serial'] = $this->serial;
$data['require_acceptance'] = $this->requireAcceptance();
if ((($this->requireAcceptance()=='1') || ($this->getEula())) && (!config('app.lock_passwords'))) {
\Mail::send('emails.accept-asset', $data, function ($m) use ($user) {
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
$m->subject('Confirm asset delivery');
});
}
}
public function checkOutNotifySlack($settings, $admin, $note = null)
{
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'Checked Out:',
'value' => 'HARDWARE asset <'.config('app.url').'/hardware/'.$this->id.'/view'.'|'.$this->showAssetName().'> checked out to <'.config('app.url').'/admin/users/'.$this->assigned_to.'/view|'.$this->assigneduser->fullName().'> by <'.config('app.url').'/admin/users/'.Auth::user()->id.'/view'.'|'.$admin->fullName().'>.'
],
[
'title' => 'Note:',
'value' => e($note)
],
]
])->send('Asset Checked Out');
} catch (Exception $e) {
LOG::error($e);
}
}
}
public function getDetailedNameAttribute()
{
if ($this->assigned_user) {
$user_name = $user->fullName();
} else {
$user_name = "Unassigned";
}
return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . $this->model->name;
}
public function validationRules($id = '0')
{
return $this->rules;
}
public function createLogRecord($action, $asset, $admin, $user, $expected_checkin = null, $note = null, $checkout_at = null)
{
$logaction = new Actionlog();
$logaction->asset_id = $this->id;
$logaction->checkedout_to = $this->assigned_to;
$logaction->asset_type = 'hardware';
$logaction->note = $note;
if ($checkout_at!='') {
$logaction->created_at = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', date('Y-m-d H:i:s', strtotime($checkout_at)));
} else {
$logaction->created_at = \Carbon\Carbon::now();
}
if ($action=="checkout") {
if ($user) {
$logaction->location_id = $user->location_id;
}
} else {
// Update the asset data to null, since it's being checked in
$logaction->checkedout_to = $asset->assigned_to;
$logaction->checkedout_to = '';
$logaction->asset_id = $asset->id;
$logaction->location_id = null;
$logaction->asset_type = 'hardware';
$logaction->note = $note;
$logaction->user_id = $admin->id;
}
$logaction->adminlog()->associate($admin);
$log = $logaction->logaction($action);
return $logaction;
}
/**
* Set depreciation relationship
*/
public function depreciation()
{
return $this->model->belongsTo('\App\Models\Depreciation', 'depreciation_id');
}
/**
* Get components assigned to this asset
*/
public function components()
{
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id')->withTrashed();
}
/**
* Get depreciation attribute from associated asset model
*/
public function get_depreciation()
{
return $this->model->depreciation;
}
/**
* Get uploads for this asset
*/
public function uploads()
{
return $this->hasMany('\App\Models\Actionlog', 'asset_id')
->where('asset_type', '=', 'hardware')
->where('action_type', '=', 'uploaded')
->whereNotNull('filename')
->orderBy('created_at', 'desc');
}
public function assigneduser()
{
return $this->belongsTo('\App\Models\User', 'assigned_to')
->withTrashed();
}
/**
* Get the asset's location based on the assigned user
**/
public function assetloc()
{
if ($this->assigneduser) {
return $this->assigneduser->userloc();
} else {
return $this->belongsTo('\App\Models\Location', 'rtd_location_id');
}
}
/**
* Get the asset's location based on default RTD location
**/
public function defaultLoc()
{
return $this->belongsTo('\App\Models\Location', 'rtd_location_id');
}
/**
* Get action logs for this asset
*/
public function assetlog()
{
return $this->hasMany('\App\Models\Actionlog', 'asset_id')
->where('asset_type', '=', 'hardware')
->orderBy('created_at', 'desc')
->withTrashed();
}
/**
* assetmaintenances
* Get improvements for this asset
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function assetmaintenances()
{
return $this->hasMany('\App\Models\AssetMaintenance', 'asset_id')
->orderBy('created_at', 'desc')
->withTrashed();
}
/**
* Get action logs for this asset
*/
public function adminuser()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
/**
* Get total assets
*/
public static function assetcount()
{
return Asset::where('physical', '=', '1')
->whereNull('deleted_at', 'and')
->count();
}
/**
* Get total assets not checked out
*/
public static function availassetcount()
{
return Asset::RTD()
->whereNull('deleted_at')
->count();
}
/**
* Get requestable assets
*/
public static function getRequestable()
{
return Asset::Requestable()
->whereNull('deleted_at')
->count();
}
/**
* Get asset status
*/
public function assetstatus()
{
return $this->belongsTo('\App\Models\Statuslabel', 'status_id');
}
/**
* Get name for EULA
**/
public function showAssetName()
{
if ($this->name == '') {
return $this->model->name;
} else {
return $this->name;
}
}
public function warrantee_expires()
{
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->warranty_months . ' months'));
return date_format($date, 'Y-m-d');
}
public function model()
{
return $this->belongsTo('\App\Models\AssetModel', 'model_id')->withTrashed();
}
public static function getExpiringWarrantee($days = 30)
{
return Asset::where('archived', '=', '0')
->whereNotNull('warranty_months')
->whereNotNull('purchase_date')
->whereNull('deleted_at')
->whereRaw(\DB::raw('DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH) <= DATE(NOW() + INTERVAL '
. $days
. ' DAY) AND DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH) > NOW()'))
->orderBy('purchase_date', 'ASC')
->get();
}
/**
* Get the license seat information
**/
public function licenses()
{
return $this->belongsToMany('\App\Models\License', 'license_seats', 'asset_id', 'license_id');
}
public function licenseseats()
{
return $this->hasMany('\App\Models\LicenseSeat', 'asset_id');
}
public function supplier()
{
return $this->belongsTo('\App\Models\Supplier', 'supplier_id');
}
public function months_until_eol()
{
$today = date("Y-m-d");
$d1 = new DateTime($today);
$d2 = new DateTime($this->eol_date());
if ($this->eol_date() > $today) {
$interval = $d2->diff($d1);
} else {
$interval = null;
}
return $interval;
}
public function eol_date()
{
if (( $this->purchase_date ) && ( $this->model )) {
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->model->eol . ' months'));
return date_format($date, 'Y-m-d');
}
}
/**
* Get auto-increment
*/
public static function autoincrement_asset()
{
$settings = \App\Models\Setting::getSettings();
if ($settings->auto_increment_assets == '1') {
$asset_tag = \DB::table('assets')
->where('physical', '=', '1')
->max('id');
return $settings->auto_increment_prefix.($asset_tag + 1);
} else {
return false;
}
}
public function checkin_email()
{
return $this->model->category->checkin_email;
}
public function requireAcceptance()
{
return $this->model->category->require_acceptance;
}
public function getEula()
{
$Parsedown = new \Parsedown();
if ($this->model->category->eula_text) {
return $Parsedown->text(e($this->model->category->eula_text));
} elseif ($this->model->category->use_default_eula == '1') {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
}
}
/**
* -----------------------------------------------
* BEGIN QUERY SCOPES
* -----------------------------------------------
**/
/**
* Query builder scope for hardware
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeHardware($query)
{
return $query->where('physical', '=', '1');
}
/**
* Query builder scope for pending assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopePending($query)
{
return $query->whereHas('assetstatus', function ($query) {
$query->where('deployable', '=', 0)
->where('pending', '=', 1)
->where('archived', '=', 0);
});
}
/**
* Query builder scope for pending assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeAssetsByLocation($query, $location)
{
return $query->where(function ($query) use ($location) {
$query->whereHas('assigneduser', function ($query) use ($location) {
$query->where('users.location_id', '=', $location->id);
})->orWhere(function ($query) use ($location) {
$query->where('assets.rtd_location_id', '=', $location->id);
$query->whereNull('assets.assigned_to');
});
});
}
/**
* Query builder scope for RTD assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeRTD($query)
{
return $query->whereNULL('assigned_to')
->whereHas('assetstatus', function ($query) {
$query->where('deployable', '=', 1)
->where('pending', '=', 0)
->where('archived', '=', 0);
});
}
/**
* Query builder scope for Undeployable assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeUndeployable($query)
{
return $query->whereHas('assetstatus', function ($query) {
$query->where('deployable', '=', 0)
->where('pending', '=', 0)
->where('archived', '=', 0);
});
}
/**
* Query builder scope for Archived assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeArchived($query)
{
return $query->whereHas('assetstatus', function ($query) {
$query->where('deployable', '=', 0)
->where('pending', '=', 0)
->where('archived', '=', 1);
});
}
/**
* Query builder scope for Deployed assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeDeployed($query)
{
return $query->where('assigned_to', '>', '0');
}
/**
* Query builder scope for Requestable assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeRequestableAssets($query)
{
return $query->where('requestable', '=', 1)
->whereHas('assetstatus', function ($query) {
$query->where('deployable', '=', 1)
->where('pending', '=', 0)
->where('archived', '=', 0);
});
}
/**
* Query builder scope for Deleted assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeDeleted($query)
{
return $query->whereNotNull('deleted_at');
}
/**
* scopeInModelList
* Get all assets in the provided listing of model ids
*
* @param $query
* @param array $modelIdListing
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function scopeInModelList($query, array $modelIdListing)
{
return $query->whereIn('model_id', $modelIdListing);
}
/**
* Query builder scope to get not-yet-accepted assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeNotYetAccepted($query)
{
return $query->where("accepted", "=", "pending");
}
/**
* Query builder scope to get rejected assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeRejected($query)
{
return $query->where("accepted", "=", "rejected");
}
/**
* Query builder scope to get accepted assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeAccepted($query)
{
return $query->where("accepted", "=", "accepted");
}
/**
* Query builder scope to search on text for complex Bootstrap Tables API
*
* @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)
{
$search = explode(' OR ', $search);
return $query->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('model', function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('categories.name', 'LIKE', '%'.$search.'%')
->orWhere('models.name', 'LIKE', '%'.$search.'%')
->orWhere('models.modelno', 'LIKE', '%'.$search.'%');
});
});
})->orWhereHas('model', function ($query) use ($search) {
$query->whereHas('manufacturer', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
});
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assetstatus', function ($query) use ($search) {
$query->where('status_labels.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('defaultLoc', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('assigneduser', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('users.last_name', 'LIKE', '%'.$search.'%')
->orWhere(function ($query) use ($search) {
$query->whereHas('userloc', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
});
});
});
})->orWhere('assets.name', 'LIKE', '%'.$search.'%')
->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%')
->orWhere('assets.serial', 'LIKE', '%'.$search.'%')
->orWhere('assets.order_number', 'LIKE', '%'.$search.'%')
->orWhere('assets.notes', 'LIKE', '%'.$search.'%');
}
foreach (CustomField::all() as $field) {
$query->orWhere($field->db_column_name(), 'LIKE', "%$search%");
}
});
}
/**
* Query builder scope to order on model
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderModels($query, $order)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')->orderBy('models.name', $order);
}
/**
* Query builder scope to order on model number
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderModelNumber($query, $order)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')->orderBy('models.modelno', $order);
}
/**
* Query builder scope to order on assigned user
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderAssigned($query, $order)
{
return $query->join('users', 'assets.assigned_to', '=', 'users.id')->orderBy('users.first_name', $order)->orderBy('users.last_name', $order);
}
/**
* Query builder scope to order on status
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderStatus($query, $order)
{
return $query->join('status_labels', 'assets.status_id', '=', 'status_labels.id')->orderBy('status_labels.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCompany($query, $order)
{
return $query->leftJoin('companies', 'assets.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
}
/**
* Query builder scope to order on category
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCategory($query, $order)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')
->join('categories', 'models.category_id', '=', 'categories.id')
->orderBy('categories.name', $order);
}
/**
* Query builder scope to order on manufacturer
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderManufacturer($query, $order)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')
->join('manufacturers', 'models.manufacturer_id', '=', 'manufacturers.id')
->orderBy('manufacturers.name', $order);
}
/**
* Query builder scope to order on location
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
* TODO: Extend this method out for checked out assets as well. Right now it
* only checks the location name related to rtd_location_id
*/
public function scopeOrderLocation($query, $order)
{
return $query->join('locations', 'locations.id', '=', 'assets.rtd_location_id')->orderBy('locations.name', $order);
}
}
+138
View File
@@ -0,0 +1,138 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Lang;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Model for Asset Maintenances.
*
* @version v1.0
*/
class AssetMaintenance extends Model implements ICompanyableChild
{
use SoftDeletes;
use CompanyableChildTrait;
use ValidatingTrait;
protected $dates = [ 'deleted_at' ];
protected $table = 'asset_maintenances';
// Declaring rules for form validation
protected $rules = [
'asset_id' => 'required|integer',
'supplier_id' => 'required|integer',
'asset_maintenance_type' => 'required',
'title' => 'required|max:100',
'is_warranty' => 'boolean',
'start_date' => 'required|date_format:Y-m-d',
'completion_date' => 'date_format:Y-m-d',
'notes' => 'string',
'cost' => 'numeric'
];
public function getCompanyableParents()
{
return [ 'asset' ];
}
/**
* getImprovementOptions
*
* @return array
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public static function getImprovementOptions()
{
return [
trans('admin/asset_maintenances/general.maintenance') => trans('admin/asset_maintenances/general.maintenance'),
trans('admin/asset_maintenances/general.repair') => trans('admin/asset_maintenances/general.repair'),
trans('admin/asset_maintenances/general.upgrade') => trans('admin/asset_maintenances/general.upgrade')
];
}
/**
* asset
* Get asset for this improvement
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function asset()
{
return $this->belongsTo('\App\Models\Asset', 'asset_id')
->withTrashed();
}
/**
* Get the admin who created the maintenance
*
* @return mixed
* @author A. Gianotto <snipe@snipe.net>
* @version v3.0
*/
public function admin()
{
return $this->belongsTo('\App\Models\User', 'user_id')
->withTrashed();
}
public function supplier()
{
return $this->belongsTo('\App\Models\Supplier', 'supplier_id')
->withTrashed();
}
/**
* -----------------------------------------------
* BEGIN QUERY SCOPES
* -----------------------------------------------
**/
/**
* 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('title', 'LIKE', '%'.$search.'%')
->orWhere('notes', 'LIKE', '%'.$search.'%')
->orWhere('asset_maintenance_type', 'LIKE', '%'.$search.'%')
->orWhere('cost', 'LIKE', '%'.$search.'%')
->orWhere('start_date', 'LIKE', '%'.$search.'%')
->orWhere('completion_date', 'LIKE', '%'.$search.'%');
});
}
/**
* Query builder scope to order on admin user
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderAdmin($query, $order)
{
return $query->leftJoin('users', 'asset_maintenances.user_id', '=', 'users.id')
->orderBy('users.first_name', $order)
->orderBy('users.last_name', $order);
}
}
+164
View File
@@ -0,0 +1,164 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Model for Asset Models. Asset Models contain higher level
* attributes that are common among the same type of asset.
*
* @version v1.0
*/
class AssetModel extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'models';
// Declare the rules for the model validation
protected $rules = array(
'name' => 'required|min:1|max:255',
'modelno' => 'min:1|max:255',
'category_id' => 'required|integer',
'manufacturer_id' => 'required|integer',
'eol' => 'integer:min:0|max:240',
'user_id' => 'integer',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','manufacturer_id','category_id','eol'];
public function assets()
{
return $this->hasMany('\App\Models\Asset', 'model_id');
}
public function category()
{
return $this->belongsTo('\App\Models\Category', 'category_id');
}
public function depreciation()
{
return $this->belongsTo('\App\Models\Depreciation', 'depreciation_id');
}
public function adminuser()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
public function manufacturer()
{
return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id');
}
public function fieldset()
{
return $this->belongsTo('\App\Models\CustomFieldset', 'fieldset_id');
}
public function getNote()
{
$Parsedown = new \Parsedown();
if ($this->note) {
return $Parsedown->text(e($this->note));
}
}
public function displayModelName()
{
$name = $this->manufacturer->name.' '.$this->name;
if ($this->modelno) {
$name .=" / ".$this->modelno;
}
return $name;
}
/**
* -----------------------------------------------
* BEGIN QUERY SCOPES
* -----------------------------------------------
**/
/**
* Query builder scope for Deleted assets
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeDeleted($query)
{
return $query->whereNotNull('deleted_at');
}
/**
* scopeInCategory
* Get all models that are in the array of category ids
*
* @param $query
* @param array $categoryIdListing
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function scopeInCategory($query, array $categoryIdListing)
{
return $query->whereIn('category_id', $categoryIdListing);
}
/**
* 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('name', 'LIKE', "%$search%")
->orWhere('modelno', 'LIKE', "%$search%")
->orWhere(function ($query) use ($search) {
$query->whereHas('depreciation', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
});
})
->orWhere(function ($query) use ($search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
});
})
->orWhere(function ($query) use ($search) {
$query->whereHas('manufacturer', function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
});
});
}
}
+143
View File
@@ -0,0 +1,143 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Model for Categories. Categories are a higher-level group
* than Asset Models, and handle things like whether or not
* to require acceptance from the user, whether or not to
* send a EULA to the user, etc.
*
* @version v1.0
*/
class Category extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'categories';
/**
* Category validation rules
*/
public $rules = array(
'user_id' => 'numeric',
'name' => 'required|min:1|max:255|unique:categories,name,NULL,deleted_at',
'category_type' => 'required',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','category_type'];
public function has_models()
{
return $this->hasMany('\App\Models\AssetModel', 'category_id')->count();
}
public function accessories()
{
return $this->hasMany('\App\Models\Accessory');
}
public function consumables()
{
return $this->hasMany('\App\Models\Consumable');
}
public function components()
{
return $this->hasMany('\App\Models\Component');
}
public function itemCount()
{
switch ($this->category_type) {
case 'asset':
return $this->assets->count();
case 'accessory':
return $this->accessories->count();
case 'component':
return $this->components->count();
case 'consumable':
return $this->consumables->count();
}
return '0';
}
public function assets()
{
return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'category_id', 'model_id');
}
public function models()
{
return $this->hasMany('\App\Models\AssetModel', 'category_id');
}
public function getEula()
{
$Parsedown = new \Parsedown();
if ($this->eula_text) {
return $Parsedown->text(e($this->eula_text));
} elseif ((Setting::getSettings()->default_eula_text) && ($this->use_default_eula=='1')) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
}
}
/**
* scopeRequiresAcceptance
*
* @param $query
*
* @return mixed
* @author Vincent Sposato <vincent.sposato@gmail.com>
* @version v1.0
*/
public function scopeRequiresAcceptance($query)
{
return $query->where('require_acceptance', '=', 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.'%')
->orWhere('category_type', 'LIKE', '%'.$search.'%');
});
}
}
+173
View File
@@ -0,0 +1,173 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait;
use Auth;
use DB;
/**
* Model for Companies.
*
* @version v1.8
*/
final class Company extends Model
{
protected $table = 'companies';
// Declare the rules for the model validation
protected $rules = ['name' => 'required|min:1|max:255|unique:companies,name'];
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
private static function isFullMultipleCompanySupportEnabled()
{
$settings = Setting::getSettings();
// NOTE: this can happen when seeding the database
if (is_null($settings)) {
return false;
} else {
return $settings->full_multiple_companies_support == 1;
}
}
private static function scopeCompanyablesDirectly($query, $column = 'company_id')
{
if (Auth::user()) {
$company_id = Auth::user()->company_id;
} else {
$company_id = null;
}
if ($company_id == null) {
return $query;
} else {
return $query->where($column, '=', $company_id);
}
}
public static function getSelectList()
{
$select_company = trans('general.select_company');
return ['0' => $select_company] + DB::table('companies')->orderBy('name', 'ASC')->lists('name', 'id');
}
public static function getIdFromInput($unescaped_input)
{
$escaped_input = e($unescaped_input);
if ($escaped_input == '0') {
return null;
} else {
return $escaped_input;
}
}
public static function getIdForCurrentUser($unescaped_input)
{
if (!static::isFullMultipleCompanySupportEnabled()) {
return static::getIdFromInput($unescaped_input);
} else {
$current_user = Auth::user();
if ($current_user->company_id != null) {
return $current_user->company_id;
} else {
return static::getIdFromInput($unescaped_input);
}
}
}
public static function isCurrentUserHasAccess($companyable)
{
if (is_null($companyable)) {
return false;
} elseif (!static::isFullMultipleCompanySupportEnabled()) {
return true;
} else {
$current_user_company_id = Auth::user()->company_id;
$companyable_company_id = $companyable->company_id;
return ($current_user_company_id == null || $current_user_company_id == $companyable_company_id || Auth::user()->isSuperUser());
}
}
public static function isCurrentUserAuthorized()
{
return ((!static::isFullMultipleCompanySupportEnabled()) || (Auth::user()->company_id == null) || (Auth::user()->isSuperUser()));
}
public static function canManageUsersCompanies()
{
return (!static::isFullMultipleCompanySupportEnabled() || Auth::user()->isSuperUser() ||
Auth::user()->company_id == null);
}
public static function getIdForUser($unescaped_input)
{
if (!static::isFullMultipleCompanySupportEnabled() || Auth::user()->isSuperUser()) {
return static::getIdFromInput($unescaped_input);
} else {
return static::getIdForCurrentUser($unescaped_input);
}
}
public static function scopeCompanyables($query, $column = 'company_id')
{
if (!static::isFullMultipleCompanySupportEnabled() || (Auth::check() && Auth::user()->isSuperUser())) {
return $query;
} else {
return static::scopeCompanyablesDirectly($query, $column);
}
}
public static function scopeCompanyableChildren(array $companyable_names, $query)
{
if (count($companyable_names) == 0) {
throw new Exception('No Companyable Children to scope');
} elseif (!static::isFullMultipleCompanySupportEnabled()) {
return $query;
} else {
$f = function ($q) {
static::scopeCompanyablesDirectly($q);
};
$q = $query->where(function ($q) use ($companyable_names, $f) {
$q2 = $q->whereHas($companyable_names[0], $f);
for ($i = 1; $i < count($companyable_names); $i++) {
$q2 = $q2->orWhereHas($companyable_names[$i], $f);
}
});
return $q;
}
}
public static function getName($companyable)
{
$company = $companyable->company;
if (is_null($company)) {
return '';
} else {
return e($company->name);
}
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
/**
* Handle query scoping for full company support.
*
* @todo Move this to a more Laravel 5.2 esque way
* @version v1.0
*/
final class CompanyableChildScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$model = $builder->getModel();
return Company::scopeCompanyableChildren($model->getCompanyableParents(), $builder);
}
/**
* @todo IMPLEMENT
* Remove the scope from the given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function remove(Builder $builder)
{
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Models;
trait CompanyableChildTrait
{
/**
* Boot the companyable trait for a model.
*
* @return void
*/
public static function bootCompanyableChildTrait()
{
static::addGlobalScope(new CompanyableChildScope);
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
/**
* Handle query scoping for full company support.
*
* @todo Move this to a more Laravel 5.2 esque way
* @version v1.0
*/
final class CompanyableScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function apply(Builder $builder, Model $model)
{
return Company::scopeCompanyables($builder);
}
/**
* @todo IMPLEMENT
* Remove the scope from the given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function remove(Builder $builder)
{
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Models;
trait CompanyableTrait
{
/**
* Boot the companyable trait for a model.
*
* @return void
*/
public static function bootCompanyableTrait()
{
static::addGlobalScope(new CompanyableScope);
}
}
+186
View File
@@ -0,0 +1,186 @@
<?php
namespace App\Models;
use App\Models\User;
use App\Models\ConsumableAssignment;
use App\Models\Company;
use App\Models\Location;
use App\Models\Category;
use App\Models\ActionLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Model for Components.
*
* @version v1.0
*/
class Component extends Model
{
use SoftDeletes;
use CompanyableTrait;
protected $dates = ['deleted_at'];
protected $table = 'components';
/**
* Category validation rules
*/
public $rules = array(
'name' => 'required|min:3|max:255',
'total_qty' => 'required|integer|min:1',
'category_id' => 'required|integer',
'company_id' => 'integer',
'purchase_date' => 'date',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','company_id','category_id'];
public function location()
{
return $this->belongsTo('\App\Models\Location', 'location_id');
}
public function assets()
{
return $this->belongsToMany('\App\Models\Asset', 'components_assets')->withPivot('assigned_qty', 'created_at', 'user_id');
}
public function admin()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
public function company()
{
return $this->belongsTo('\App\Models\Company', 'company_id');
}
public function category()
{
return $this->belongsTo('\App\Models\Category', 'category_id');
}
/**
* Get action logs for this consumable
*/
public function assetlog()
{
return $this->hasMany('\App\Models\Actionlog', 'component_id')->where('asset_type', '=', 'component')->orderBy('created_at', 'desc')->withTrashed();
}
public function numRemaining()
{
$checkedout = 0;
foreach ($this->assets as $checkout) {
$checkedout += $checkout->pivot->assigned_qty;
}
$total = $this->total_qty;
$remaining = $total - $checkedout;
return $remaining;
}
/**
* 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
*/
/**
* 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)
{
$search = explode(' ', $search);
return $query->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('categories.name', 'LIKE', '%'.$search.'%');
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('location', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere('components.name', 'LIKE', '%'.$search.'%')
->orWhere('components.order_number', 'LIKE', '%'.$search.'%')
->orWhere('components.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('components.purchase_date', 'LIKE', '%'.$search.'%');
}
});
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCategory($query, $order)
{
return $query->join('categories', 'components.category_id', '=', 'categories.id')->orderBy('categories.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderLocation($query, $order)
{
return $query->leftJoin('locations', 'components.location_id', '=', 'locations.id')->orderBy('locations.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCompany($query, $order)
{
return $query->leftJoin('companies', 'components.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
}
}
+227
View File
@@ -0,0 +1,227 @@
<?php
namespace App\Models;
use App\Models\User;
use App\Models\ConsumableAssignment;
use App\Models\Company;
use App\Models\Location;
use App\Models\Category;
use App\Models\ActionLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
class Consumable extends Model
{
use SoftDeletes;
use CompanyableTrait;
protected $dates = ['deleted_at'];
protected $table = 'consumables';
/**
* Category validation rules
*/
public $rules = array(
'name' => 'required|min:3|max:255',
'qty' => 'required|integer|min:0',
'category_id' => 'required|integer',
'company_id' => 'integer',
'min_amt' => 'integer|min:1',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','qty','company_id','category_id'];
public function admin()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
public function consumableAssigments()
{
return $this->hasMany('\App\Models\ConsumableAssignment');
}
public function company()
{
return $this->belongsTo('\App\Models\Company', 'company_id');
}
public function manufacturer()
{
return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id');
}
public function location()
{
return $this->belongsTo('\App\Models\Location', 'location_id');
}
public function category()
{
return $this->belongsTo('\App\Models\Category', 'category_id');
}
/**
* Get action logs for this consumable
*/
public function assetlog()
{
return $this->hasMany('\App\Models\Actionlog', 'consumable_id')->where('asset_type', '=', 'consumable')->orderBy('created_at', 'desc')->withTrashed();
}
public function users()
{
return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps();
}
public function hasUsers()
{
return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->count();
}
public function requireAcceptance()
{
return $this->category->require_acceptance;
}
public function getEula()
{
$Parsedown = new \Parsedown();
if ($this->category->eula_text) {
return $Parsedown->text(e($this->category->eula_text));
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula=='1')) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
}
}
public function numRemaining()
{
$checkedout = $this->users->count();
$total = $this->qty;
$remaining = $total - $checkedout;
return $remaining;
}
/**
* 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
*/
/**
* 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)
{
$search = explode(' ', $search);
return $query->where(function ($query) use ($search) {
foreach ($search as $search) {
$query->whereHas('category', function ($query) use ($search) {
$query->where('categories.name', 'LIKE', '%'.$search.'%');
})->orWhere(function ($query) use ($search) {
$query->whereHas('company', function ($query) use ($search) {
$query->where('companies.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('location', function ($query) use ($search) {
$query->where('locations.name', 'LIKE', '%'.$search.'%');
});
})->orWhere(function ($query) use ($search) {
$query->whereHas('manufacturer', function ($query) use ($search) {
$query->where('manufacturers.name', 'LIKE', '%'.$search.'%');
});
})->orWhere('consumables.name', 'LIKE', '%'.$search.'%')
->orWhere('consumables.order_number', 'LIKE', '%'.$search.'%')
->orWhere('consumables.purchase_cost', 'LIKE', '%'.$search.'%')
->orWhere('consumables.purchase_date', 'LIKE', '%'.$search.'%');
}
});
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCategory($query, $order)
{
return $query->join('categories', 'consumables.category_id', '=', 'categories.id')->orderBy('categories.name', $order);
}
/**
* Query builder scope to order on location
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderLocation($query, $order)
{
return $query->leftJoin('locations', 'consumables.location_id', '=', 'locations.id')->orderBy('locations.name', $order);
}
/**
* Query builder scope to order on manufacturer
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderManufacturer($query, $order)
{
return $query->leftJoin('manufacturers', 'consumables.manufacturer_id', '=', 'manufacturers.id')->orderBy('manufacturers.name', $order);
}
/**
* Query builder scope to order on company
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderCompany($query, $order)
{
return $query->leftJoin('companies', 'consumables.company_id', '=', 'companies.id')->orderBy('companies.name', $order);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ConsumableAssignment extends Model
{
use CompanyableTrait;
protected $dates = ['deleted_at'];
protected $table = 'consumables_users';
public function consumable()
{
return $this->belongsTo('\App\Models\Consumable');
}
public function user()
{
return $this->belongsTo('\App\Models\User', 'assigned_to');
}
public function admin()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
}
+112
View File
@@ -0,0 +1,112 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CustomField extends Model
{
public $guarded=["id"];
/**
*/
public static $PredefinedFormats=[
"ANY" => "",
"ALPHA" => "alpha",
"EMAIL" => "email",
"DATE" => "date",
"URL" => "url",
"NUMERIC" => "numeric",
"MAC" => "regex:/^[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}$/",
"IP" => "ip"
];
public $rules=[
"name" => "required|unique:custom_fields"
];
public static $table_name="assets";
public static function name_to_db_name($name)
{
return "_snipeit_".preg_replace("/[^a-zA-Z0-9]/", "_", strtolower($name));
}
public static function boot()
{
self::creating(function ($custom_field) {
if (in_array($custom_field->db_column_name(), \Schema::getColumnListing(\DB::getTablePrefix().CustomField::$table_name))) {
//field already exists when making a new custom field; fail.
return false;
}
\Schema::table(\DB::getTablePrefix().\App\Models\CustomField::$table_name, function ($table) use ($custom_field) {
$table->text($custom_field->db_column_name())->nullable();
});
});
self::updating(function ($custom_field) {
if ($custom_field->isDirty("name")) {
if (in_array($custom_field->db_column_name(), \Schema::getColumnListing(CustomField::$table_name))) {
//field already exists when renaming a custom field
return false;
}
return \DB::statement("UPDATE ".CustomField::$table_name." RENAME ".self::name_to_db_name($custom_field->get_original("name"))." TO ".$custom_field->db_column_name());
}
return true;
});
self::deleting(function ($custom_field) {
return \DB::statement("ALTER TABLE ".CustomField::$table_name." DROP COLUMN ".$custom_field->db_column_name());
});
}
public function fieldset()
{
return $this->belongsToMany('\App\Models\CustomFieldset'); //?!?!?!?!?!?
}
public function user()
{
return $this->belongsTo('\App\Models\User');
}
//public function
//need helper to go from regex->English
//need helper to go from English->regex
//need helper for save() stuff - basically to alter table for the fields in question
public function check_format($value)
{
return preg_match('/^'.$this->attributes['format'].'$/', $value)===1;
}
public function db_column_name()
{
return self::name_to_db_name($this->name);
}
//mutators for 'format' attribute
public function getFormatAttribute($value)
{
foreach (self::$PredefinedFormats as $name => $pattern) {
if ($pattern===$value) {
return $name;
}
}
return $value;
}
public function setFormatAttribute($value)
{
if (isset(self::$PredefinedFormats[$value])) {
$this->attributes['format']=self::$PredefinedFormats[$value];
} else {
$this->attributes['format']=$value;
}
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CustomFieldset extends Model
{
protected $guarded=["id"];
public $rules=[
"name" => "required|unique:custom_fieldsets"
];
public function fields()
{
return $this->belongsToMany('\App\Models\CustomField')->withPivot(["required","order"])->orderBy("pivot_order");
}
public function models()
{
return $this->hasMany('\App\Models\AssetModel', "fieldset_id");
}
public function user()
{
return $this->belongsTo('\App\Models\User'); //WARNING - not all CustomFieldsets have a User!!
}
public function validation_rules()
{
$rules=[];
foreach ($this->fields as $field) {
$rule=[];
if ($field->pivot->required) {
$rule[]="required";
}
array_push($rule, $field->attributes['format']);
$rules[$field->db_column_name()]=$rule;
}
return $rules;
}
//requiredness goes *here*
//sequence goes here?
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Depreciation;
class Depreciable extends Model
{
/**
* Depreciation Relation, and associated helper methods
*/
//REQUIRES a purchase_date field
// and a purchase_cost field
//REQUIRES a get_depreciation method,
//which will return the deprecation.
//this is needed because assets get
//their depreciation from a model,
//whereas licenses have deprecations
//directly associated with them.
//assets will override the following
//two methods in order to inherit from
//their model instead of directly (like
//here)
public function depreciation()
{
return $this->belongsTo('\App\Models\Depreciation', 'depreciation_id');
}
public function get_depreciation()
{
return $this->depreciation;
}
/**
* @return float|int
*/
public function getDepreciatedValue()
{
if (!$this->get_depreciation()) { // will never happen
return $this->purchase_cost;
}
if ($this->get_depreciation()->months <= 0) {
return $this->purchase_cost;
}
// fraction of value left
$months_remaining = $this->time_until_depreciated()->m + 12*$this->time_until_depreciated()->y; //UGlY
$current_value = round(($months_remaining/ $this->get_depreciation()->months) * $this->purchase_cost, 2);
if ($current_value < 0) {
$current_value = 0;
}
return $current_value;
}
public function time_until_depreciated()
{
// @link http://www.php.net/manual/en/class.datetime.php
$d1 = new \DateTime();
$d2 = $this->depreciated_date();
// @link http://www.php.net/manual/en/class.dateinterval.php
$interval = $d1->diff($d2);
if (!$interval->invert) {
return $interval;
} else {
return new \DateInterval("PT0S"); //null interval (zero seconds from now)
}
}
public function depreciated_date()
{
$date = date_create($this->purchase_date);
date_add($date, date_interval_create_from_date_string($this->get_depreciation()->months . ' months'));
return $date; //date_format($date, 'Y-m-d'); //don't bake-in format, for internationalization
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait;
class Depreciation extends Model
{
// Declare the rules for the form validation
protected $rules = array(
'name' => 'required|min:3|max:255|unique:depreciations,name',
'months' => 'required|max:240|integer',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name','months'];
public function has_models()
{
return $this->hasMany('\App\Models\AssetModel', 'depreciation_id')->count();
}
public function has_licenses()
{
return $this->hasMany('\App\Models\License', 'depreciation_id')->count();
}
/**
* 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.'%')
->orWhere('months', 'LIKE', '%'.$search.'%');
});
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Model;
class Group extends Model
{
protected $table = 'groups';
public $rules = array(
'name' => 'required|min:3|max:255',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* Get user groups
*/
public function users()
{
return $this->belongsToMany('\App\Models\User', 'users_groups');
}
public function decodePermissions()
{
return json_decode($this->permissions, true);
}
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace App\Models;
interface ICompanyableChild
{
public function getCompanyableParents();
}
+270
View File
@@ -0,0 +1,270 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use App\Models\Setting;
use Exception;
use Input;
use Log;
class Ldap extends Model
{
/**
* Makes a connection to LDAP using the settings in Admin > Settings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return connection
*/
public static function connectToLdap()
{
$ldap_host = Setting::getSettings()->ldap_server;
$ldap_version = Setting::getSettings()->ldap_version;
$ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore;
// If we are ignoring the SSL cert we need to setup the environment variable
// before we create the connection
if ($ldap_server_cert_ignore) {
putenv('LDAPTLS_REQCERT=never');
}
// Connecting to LDAP
$connection = @ldap_connect($ldap_host) or die("Could not connect to {$ldap_host}");
if (!$connection) {
throw new Exception('Could not connect to LDAP server at '.$ldap_host.': '.ldap_error($connection));
}
// Needed for AD
ldap_set_option($connection, LDAP_OPT_REFERRALS, 0);
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
return $connection;
}
/**
* Binds/authenticates the user to LDAP, and returns their attributes.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $username
* @param $password
* @param bool|false $user
* @return bool true if the username and/or password provided are valid
* false if the username and/or password provided are invalid
* array of ldap_attributes if $user is true
*
*/
static function findAndBindUserLdap($username, $password)
{
$settings = Setting::getSettings();
$connection = Ldap::connectToLdap();
$ldap_username_field = $settings->ldap_username_field;
$baseDn = $settings->ldap_basedn;
if ($settings->is_ad =='1')
{
// In case they haven't added an AD domain
if ($settings->ad_domain == '') {
$userDn = $username.'@'.$settings->email_domain;
} else {
$userDn = $username.'@'.$settings->ad_domain;
}
} else {
$userDn = $ldap_username_field.'='.$username.','.$settings->ldap_basedn;
}
$filterQuery = $settings->ldap_auth_filter_query . $username;
if (!$ldapbind = @ldap_bind($connection, $userDn, $password)) {
return false;
}
if (!$results = ldap_search($connection, $baseDn, $filterQuery)) {
throw new Exception('Could not search LDAP: ');
}
if (!$entry = ldap_first_entry($connection, $results)) {
return false;
}
if (!$user = array_change_key_case(ldap_get_attributes($connection, $entry), CASE_LOWER)) {
return false;
}
return $user;
}
/**
* Binds/authenticates an admin to LDAP for LDAP searching/syncing.
* Here we also return a better error if the app key is donked.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param bool|false $user
* @return bool true if the username and/or password provided are valid
* false if the username and/or password provided are invalid
*
*/
static function bindAdminToLdap($connection)
{
$ldap_username = Setting::getSettings()->ldap_uname;
// Lets return some nicer messages for users who donked their app key, and disable LDAP
try {
$ldap_pass = \Crypt::decrypt(Setting::getSettings()->ldap_pword);
} catch (Exception $e) {
throw new Exception('Your app key has changed! Could not decrypt LDAP password using your current app key, so LDAP authentication has been disabled. Login with a local account, update the LDAP password and re-enable it in Admin > Settings.');
}
if (!$ldapbind = @ldap_bind($connection, $ldap_username, $ldap_pass)) {
throw new Exception('Could not bind to LDAP: '.ldap_error($connection));
}
}
/**
* Parse and map LDAP attributes based on settings
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
*
* @param $ldapatttibutes
* @return array|bool
*/
static function parseAndMapLdapAttributes($ldapatttibutes)
{
//Get LDAP attribute config
$ldap_result_username = Setting::getSettings()->ldap_username_field;
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
$ldap_result_email = Setting::getSettings()->ldap_email;
// Get LDAP user data
$item = array();
$item["username"] = isset($ldapatttibutes[$ldap_result_username][0]) ? $ldapatttibutes[$ldap_result_username][0] : "";
$item["employee_number"] = isset($ldapatttibutes[$ldap_result_emp_num][0]) ? $ldapatttibutes[$ldap_result_emp_num][0] : "";
$item["lastname"] = isset($ldapatttibutes[$ldap_result_last_name][0]) ? $ldapatttibutes[$ldap_result_last_name][0] : "";
$item["firstname"] = isset($ldapatttibutes[$ldap_result_first_name][0]) ? $ldapatttibutes[$ldap_result_first_name][0] : "";
$item["email"] = isset($ldapatttibutes[$ldap_result_email][0]) ? $ldapatttibutes[$ldap_result_email][0] : "" ;
return $item;
}
/**
* Create user from LDAP attributes
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $ldapatttibutes
* @return array|bool
*/
static function createUserFromLdap($ldapatttibutes)
{
$item = Ldap::parseAndMapLdapAttributes($ldapatttibutes);
// Create user from LDAP data
if (!empty($item["username"])) {
$user = new User;
$user->first_name = $item["firstname"];
$user->last_name = $item["lastname"];
$user->username = $item["username"];
$user->email = $item["email"];
$user->password = bcrypt(Input::get("password"));
$user->activated = 1;
$user->ldap_import = 1;
$user->notes = 'Imported on first login from LDAP';
if ($user->save()) {
return true;
} else {
LOG::debug('Could not create user.'.$user->getErrors());
exit;
}
}
return false;
}
/**
* Searches LDAP
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @param $ldapatttibutes
* @return array|bool
*/
static function findLdapUsers() {
$ldapconn = Ldap::connectToLdap();
$ldap_bind = Ldap::bindAdminToLdap($ldapconn);
$base_dn = Setting::getSettings()->ldap_basedn;
$filter = Setting::getSettings()->ldap_filter;
// Set up LDAP pagination for very large databases
// @author Richard Hofman
$page_size = 500;
$cookie = '';
$result_set = array();
$global_count = 0;
// Perform the search
do {
// Paginate (non-critical, if not supported by server)
ldap_control_paged_result($ldapconn, $page_size, false, $cookie);
$search_results = ldap_search($ldapconn, $base_dn, '('.$filter.')');
if (!$search_results) {
return redirect()->route('users')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn));
}
// Get results from page
$results = ldap_get_entries($ldapconn, $search_results);
if (!$results) {
return redirect()->route('users')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn));
}
// Add results to result set
$global_count += $results['count'];
$result_set = array_merge($result_set, $results);
ldap_control_paged_result_response($ldapconn, $search_results, $cookie);
} while ($cookie !== null && $cookie != '');
// Clean up after search
$result_set['count'] = $global_count;
$results = $result_set;
ldap_control_paged_result($ldapconn, 0);
return $results;
}
}
+215
View File
@@ -0,0 +1,215 @@
<?php
namespace App\Models;
use App\Models\Company;
use DB;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\SoftDeletes;
class License extends Depreciable
{
use SoftDeletes;
use CompanyableTrait;
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
protected $dates = ['deleted_at'];
public $timestamps = true;
protected $guarded = 'id';
protected $table = 'licenses';
protected $rules = array(
'name' => 'required|string|min:3|max:255',
'serial' => 'required|min:5',
'seats' => 'required|min:1|max:10000|integer',
'license_email' => 'email|min:0|max:120',
'license_name' => 'string|min:0|max:100',
'note' => 'string',
'notes' => 'string|min:0',
'company_id' => 'integer',
);
public function company()
{
return $this->belongsTo('\App\Models\Company', 'company_id');
}
/**
* Get the assigned user
*/
public function assignedusers()
{
return $this->belongsToMany('\App\Models\User', 'license_seats', 'assigned_to', 'license_id');
}
/**
* Get asset logs for this asset
*/
public function assetlog()
{
return $this->hasMany('\App\Models\Actionlog', 'asset_id')
->where('asset_type', '=', 'software')
->orderBy('created_at', 'desc');
}
/**
* Get uploads for this asset
*/
public function uploads()
{
return $this->hasMany('\App\Models\Actionlog', 'asset_id')
->where('asset_type', '=', 'software')
->where('action_type', '=', 'uploaded')
->whereNotNull('filename')
->orderBy('created_at', 'desc');
}
/**
* Get admin user for this asset
*/
public function adminuser()
{
return $this->belongsTo('\App\Models\User', 'user_id');
}
/**
* Get total licenses
*/
public static function assetcount()
{
return LicenseSeat::whereNull('deleted_at')
->count();
}
/**
* Get total licenses
*/
public function totalSeatsByLicenseID()
{
return LicenseSeat::where('license_id', '=', $this->id)
->whereNull('deleted_at')
->count();
}
/**
* Get total licenses not checked out
*/
public static function availassetcount()
{
return LicenseSeat::whereNull('assigned_to')
->whereNull('asset_id')
->whereNull('deleted_at')
->count();
}
/**
* Get the number of available seats
*/
public function availcount()
{
return LicenseSeat::whereNull('assigned_to')
->whereNull('asset_id')
->where('license_id', '=', $this->id)
->whereNull('deleted_at')
->count();
}
/**
* Get the number of assigned seats
*
*/
public function assignedcount()
{
return \App\Models\LicenseSeat::where('license_id', '=', $this->id)
->where(function ($query) {
$query->whereNotNull('assigned_to')
->orWhereNotNull('asset_id');
})
->count();
}
public function remaincount()
{
$total = $this->totalSeatsByLicenseID();
$taken = $this->assignedcount();
$diff = ($total - $taken);
return $diff;
}
/**
* Get the total number of seats
*/
public function totalcount()
{
$avail = $this->availcount();
$taken = $this->assignedcount();
$diff = ($avail + $taken);
return $diff;
}
/**
* Get license seat data
*/
public function licenseseats()
{
return $this->hasMany('\App\Models\LicenseSeat');
}
public function supplier()
{
return $this->belongsTo('\App\Models\Supplier', 'supplier_id');
}
public function freeSeat()
{
$seat = LicenseSeat::where('license_id', '=', $this->id)
->whereNull('deleted_at')
->whereNull('assigned_to')
->whereNull('asset_id')
->first();
return $seat->id;
}
public static function getExpiringLicenses($days = 60)
{
return License::whereNotNull('expiration_date')
->whereNull('deleted_at')
->whereRaw(DB::raw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) '))
->where('expiration_date', '>', date("Y-m-d"))
->orderBy('expiration_date', 'ASC')
->get();
}
/**
* 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.'%')
->orWhere('serial', 'LIKE', '%'.$search.'%')
->orWhere('notes', 'LIKE', '%'.$search.'%')
->orWhere('order_number', 'LIKE', '%'.$search.'%')
->orWhere('purchase_date', 'LIKE', '%'.$search.'%')
->orWhere('purchase_cost', 'LIKE', '%'.$search.'%');
});
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class LicenseSeat extends Model implements ICompanyableChild
{
use CompanyableChildTrait;
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $guarded = 'id';
protected $table = 'license_seats';
public function getCompanyableParents()
{
return ['asset', 'license'];
}
public function license()
{
return $this->belongsTo('\App\Models\License', 'license_id');
}
public function user()
{
return $this->belongsTo('\App\Models\User', 'assigned_to')->withTrashed();
}
public function asset()
{
return $this->belongsTo('\App\Models\Asset', 'asset_id')->withTrashed();
}
}
+168
View File
@@ -0,0 +1,168 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\User;
use App\Models\Asset;
use Watson\Validating\ValidatingTrait;
class Location extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'locations';
protected $rules = array(
'name' => 'required|min:3|max:255|unique:locations,name,NULL,deleted_at',
'city' => 'min:3|max:255',
'state' => 'min:2|max:32',
'country' => 'min:2|max:2|max:2',
'address' => 'min:5|max:80',
'address2' => 'min:2|max:80',
'zip' => 'min:3|max:10',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
public function users()
{
return $this->hasMany('\App\Models\User', 'location_id');
}
public function assets()
{
return $this->hasManyThrough('\App\Models\Asset', '\App\Models\Actionlog', 'location_id', 'id');
}
public function assignedassets()
{
return $this->hasMany('\App\Models\Asset', 'rtd_location_id');
}
public function parent()
{
return $this->belongsTo('\App\Models\Location', 'parent_id');
}
public function childLocations()
{
return $this->hasMany('\App\Models\Location', 'parent_id');
}
public static function getLocationHierarchy($locations, $parent_id = null)
{
$op = array();
foreach ($locations as $location) {
if ($location['parent_id'] == $parent_id) {
$op[$location['id']] =
array(
'name' => $location['name'],
'parent_id' => $location['parent_id']
);
// Using recursion
$children = Location::getLocationHierarchy($locations, $location['id']);
if ($children) {
$op[$location['id']]['children'] = $children;
}
}
}
return $op;
}
public static function flattenLocationsArray($location_options_array = null)
{
$location_options = array();
foreach ($location_options_array as $id => $value) {
// get the top level key value
$location_options[$id] = $value['name'];
// If there is a key named children, it has child locations and we have to walk it
if (array_key_exists('children', $value)) {
foreach ($value['children'] as $child_id => $child_location_array) {
$child_location_options = Location::flattenLocationsArray($value['children']);
foreach ($child_location_options as $child_id => $child_name) {
$location_options[$child_id] = '--'.$child_name;
}
}
}
}
return $location_options;
}
/**
* 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('name', 'LIKE', "%$search%")
->orWhere('address', 'LIKE', "%$search%")
->orWhere('city', 'LIKE', "%$search%")
->orWhere('state', 'LIKE', "%$search%")
->orWhere('zip', 'LIKE', "%$search%")
// This doesn't actually work - need to use a table alias maybe?
->orWhere(function ($query) use ($search) {
$query->whereHas('parent', function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('name', 'LIKE', '%'.$search.'%');
});
})
// Ugly, ugly code because Laravel sucks at self-joins
->orWhere(function ($query) use ($search) {
$query->whereRaw("parent_id IN (select id from locations where name LIKE '%".$search."%') ");
});
});
}
/**
* Query builder scope to order on parent
*
* @param Illuminate\Database\Query\Builder $query Query builder instance
* @param text $order Order
*
* @return Illuminate\Database\Query\Builder Modified query builder
*/
public function scopeOrderParent($query, $order)
{
// Left join here, or it will only return results with parents
return $query->leftJoin('locations as parent_loc', 'locations.parent_id', '=', 'parent_loc.id')->orderBy('parent_loc.name', $order);
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
class Manufacturer extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'manufacturers';
// Declare the rules for the form validation
protected $rules = array(
'name' => 'required|min:2|max:255|unique:manufacturers,name,NULL,deleted_at',
'user_id' => 'integer',
);
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var boolean
*/
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
public function has_models()
{
return $this->hasMany('\App\Models\AssetModel', 'manufacturer_id')->count();
}
public function assets()
{
return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'manufacturer_id', 'model_id');
}
/**
* 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.'%');
});
}
}

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