Compare commits

..

11 Commits

Author SHA1 Message Date
snipe 158dc1f8da Squashed commit of the following:
commit e1263155b1
Merge: 886f2a0de 014eab3ab
Author: snipe <snipe@snipe.net>
Date:   Mon Jan 9 11:10:19 2023 -0800

    Merge pull request #12323 from snipe/translations/updated_strings

    Updated language strings

commit 014eab3abc
Author: snipe <snipe@snipe.net>
Date:   Mon Jan 9 11:09:26 2023 -0800

    Updated language strings

    Signed-off-by: snipe <snipe@snipe.net>

commit 886f2a0dec
Merge: 19e703980 e05764ac3
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 18:44:44 2023 -0800

    Merge pull request #12317 from snipe/fixes/shorten_url_display_on_view

    Truncate URL with ellipsis if too long

commit e05764ac34
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 18:42:26 2023 -0800

    Truncate URL with ellipsis if too long

    Signed-off-by: snipe <snipe@snipe.net>

commit 19e703980d
Merge: bd3f730cb 6e42bce40
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 18:07:30 2023 -0800

    Merge pull request #12316 from snipe/features/chunk_data_in_sync_script

    Chunk sync script

commit 6e42bce409
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 18:04:06 2023 -0800

    Removed $start variable from calback

    Signed-off-by: snipe <snipe@snipe.net>

commit 1a3c947b14
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 17:57:52 2023 -0800

    Chunk sync script

    Signed-off-by: snipe <snipe@snipe.net>

commit bd3f730cb2
Merge: ace73acba 381f89c5a
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 14:11:24 2023 -0800

    Merge pull request #12315 from snipe/features/added_default_values_to_model_api

    Features/added default values to model api

commit 381f89c5a8
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 13:15:30 2023 -0800

    Added format to array

    Signed-off-by: snipe <snipe@snipe.net>

commit db43628bdc
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 13:12:54 2023 -0800

    Added default field info to models API response

    Signed-off-by: snipe <snipe@snipe.net>

commit ace73acba1
Merge: 5898e384f 301c4fda6
Author: snipe <snipe@snipe.net>
Date:   Thu Jan 5 09:59:35 2023 -0800

    Merge pull request #12263 from Godmartinz/gh12211_label_padding_adjustment

    Fixed: page-break and padding at the end of document for labels

commit 301c4fda6e
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Jan 5 09:55:25 2023 -0800

    fixes conflicts

commit 5898e384f8
Merge: c575798b5 9c63f426d
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 15:13:36 2023 -0800

    Merge pull request #12308 from snipe/fixes/missing_translation_string

    Fixed missing translation string

commit 9c63f426d9
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 14:09:14 2023 -0800

    Added missing translation string

    Signed-off-by: snipe <snipe@snipe.net>

commit c575798b56
Merge: b36e81836 7123e7327
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 14:01:03 2023 -0800

    Merge pull request #12307 from snipe/fixes/update_less_and_css_loader

    Updated less-loader and css-loader libraries

commit 7123e7327f
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 14:00:04 2023 -0800

    Updated less-loader and css-loader libraries

    Signed-off-by: snipe <snipe@snipe.net>

commit b36e81836f
Merge: 818db58a7 b77d5801f
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 13:57:14 2023 -0800

    Merge pull request #12306 from snipe/fixes/weird_sentence_in_translations

    Fixed incomplete sentence in translation file for audit interval

commit b77d5801fa
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 13:56:16 2023 -0800

    English is hard, apparently

    Signed-off-by: snipe <snipe@snipe.net>

commit 818db58a7b
Merge: baf14c43e c4f900e9a
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 13:22:03 2023 -0800

    Merge pull request #12305 from uberbrady/fix_license_seat_reporting

    Fixed: Change license_seat changing method to properly 'true up' license seats

commit c4f900e9af
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Wed Jan 4 13:02:53 2023 -0800

    Change license_seat changing method to properly 'true up' license seats

commit baf14c43ee
Merge: d187174f0 fa439a192
Author: snipe <snipe@snipe.net>
Date:   Tue Jan 3 14:50:25 2023 -0800

    Merge pull request #12298 from snipe/fixes/db_seeder_company_id

    Fixed db seeder when company id is not present

commit fa439a1928
Author: snipe <snipe@snipe.net>
Date:   Tue Jan 3 14:45:23 2023 -0800

    Check that the array key exists before trying to seed it

    Signed-off-by: snipe <snipe@snipe.net>

commit d187174f00
Merge: 6d3c5e065 92ae27129
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 22 11:29:12 2022 -0800

    Merge pull request #12090 from Godmartinz/deparmtnet_name_validator

    Added: validation for department names at Company locations

commit 6d3c5e0659
Merge: 685cc86d7 e791e6592
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 21 19:04:11 2022 -0800

    Merge pull request #12264 from Godmartinz/gh12253_display_notes_accessories

    Added: notes to the accessories tab for user detail view

commit 685cc86d71
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:24:01 2022 -0800

    Sets the `ldap_default_group` field to nullable and default null

    Signed-off-by: snipe <snipe@snipe.net>

commit fb10a6f218
Merge: 128c21a90 3a9b8a499
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:05:18 2022 -0800

    Merge pull request #12268 from inietov/fixes/people_count

    Fixed: Dashboard user count scoping when full company support is enabled

commit 3a9b8a4993
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 20 18:39:17 2022 -0600

    Calculate the proper amount of people in the dashboard if Full Company Support is enabled

commit 128c21a905
Merge: 88291cadc 75a757d6f
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 15:09:30 2022 -0800

    Merge pull request #12266 from uberbrady/fix-select-all-bug

    Fixed: There was a bug with BS tables' select-all which showed an incorrect list of elements

commit 75a757d6f5
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Tue Dec 20 14:57:58 2022 -0800

    There was a bug with select-all where some bits didn't quite work

commit e791e6592a
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 20 10:37:19 2022 -0800

    adds notes to the accessories tab under users

commit 38575e93e8
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 20 09:45:41 2022 -0800

    fixes the rules for adding page-break and padding at the end of document

commit 88291cadc1
Merge: 399c7590c 94afe2bc6
Author: snipe <snipe@snipe.net>
Date:   Mon Dec 19 12:41:32 2022 -0800

    Merge pull request #12254 from akemidx/documentating_something

    Commenting on a scope in Models/Company.php

commit 94afe2bc6a
Author: akemidx <kojotek.dx@gmail.com>
Date:   Mon Dec 19 14:48:43 2022 -0500

    edits & typo fixes

commit 399c7590cd
Merge: d0c5ba70f eb67d1b06
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 14:19:41 2022 -0800

    Merge pull request #12209 from snipe/fixes/error_downloading_unaccepted_assets

    Fixed 500 when downloading the Unaccepted Assets report  [sc-19555]

commit d0c5ba70f6
Merge: 29c2ff56e d9a21cce0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 12:42:29 2022 -0800

    Merge pull request #12242 from inietov/features/add_purchase_cost_column

    Added `purchase_cost` to user's default view [sc-19680]

commit 133d6ffa50
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 15:18:24 2022 -0500

    Commenting on a scope in Models/Company.php

commit d9a21cce00
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Thu Dec 15 14:12:05 2022 -0600

    Add other items' purchase_cost columns to the same permission

commit 29c2ff56ec
Merge: 3e7975b2c 1fe0bfe17
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:26:49 2022 -0800

    Merge pull request #12188 from snipe/fixes/decrease_logging_for_saml_when_not_enabled

    Removed extra logging case that was very noisy

commit 3e7975b2c3
Merge: 227fef76e d870bc3b0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:25:53 2022 -0800

    Merge pull request #12250 from akemidx/grey_out_pw_reset_button

    Fixed: Grey out pw reset button for consistency

commit d870bc3b02
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 14:19:51 2022 -0500

    nested if loop

commit 227fef76ee
Merge: 418ddcfac 9d44720ff
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:06:53 2022 -0800

    Merge pull request #11736 from Godmartinz/gh6508_ldap_default_group

    Adds a permission group selection for directory sync

commit 9d44720ffd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 11:02:34 2022 -0800

    reverted changes to composer.lock

commit 9f3f0a25ed
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:53:45 2022 -0800

    reverted changes to composer.lock

commit 2e228ccb0b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:45:42 2022 -0800

    redid a few things. should be good now :)

commit 3ee413f379
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 09:20:30 2022 -0800

    removes livewire stuff

commit b142f8e012
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Wed Dec 14 23:00:35 2022 -0600

    Add the permission to show purchase cost column to non-admin sessions

commit 418ddcfac3
Merge: c342668f0 1a908e361
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:46:53 2022 -0800

    Merge pull request #9876 from Toreg87/fixes/locations-deletable

    Fixed #9875: Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

commit c342668f0f
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:39 2022 -0800

    Update @scoo73r as a contributor

commit 2f6a26ec7d
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:25 2022 -0800

    Add @scoo73r as a contributor

commit f635278010
Merge: d13a23700 8043b8678
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:42:41 2022 -0800

    Merge pull request #12251 from snipe/security/upgrade_font_awesome

    Upgraded font awesome to 6.2.1

commit 8043b86786
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:41:56 2022 -0800

    Upgraded font awesome to 6.2.1

    Signed-off-by: snipe <snipe@snipe.net>

commit d13a237000
Merge: fabefa61b d0d0058e7
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 12:13:18 2022 -0800

    Merge pull request #12205 from Godmartinz/sc19675_add_remote_to_importer

    Adds remote field to the user importer

commit b114ffd2c3
Author: akemidx <kojotek.dx@gmail.com>
Date:   Wed Dec 14 14:48:59 2022 -0500

    Grey out button pw reset button for consistency

    When user has no email in their profile, the box is greyed out for
    consistency accross all buttons on the user profile

commit fabefa61b0
Merge: 389ec3a3c f3e57d7dc
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 14:00:48 2022 -0800

    Merge pull request #12243 from akemidx/new_grey_out_when_no_assets

    Created method in users.php for adding up all assigned to user and pr…

commit f3e57d7dc0
Author: akemidx <kojotek.dx@gmail.com>
Date:   Tue Dec 13 16:00:59 2022 -0500

    fixing PR

commit 389ec3a3cb
Merge: c432fb9d7 6a72c344b
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 12:57:50 2022 -0800

    Merge pull request #12247 from Godmartinz/gh12225_serial_added_to_components

    adds serial to components tab of assets

commit 6a72c344b7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 12:32:30 2022 -0800

    removed the cuddlers

commit 4442b446b9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 10:30:37 2022 -0800

    adds serial to components tab of assets

commit c432fb9d70
Merge: 9e8fff6e5 fa872b09a
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 10:28:17 2022 -0800

    Merge pull request #12181 from Godmartinz/gh12163_asset_age

    Adds asset age to asset index and asset view pages

commit 07ae91b00f
Author: akemi <akemi@ShibaPro.local>
Date:   Wed Dec 7 17:46:18 2022 -0500

    Created method in users.php for adding up all assigned to user and providing an integer value. this then used to grey out buttons on user view if user has nothing assigned.

commit 450ad3dcec
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Mon Dec 12 14:17:08 2022 -0600

    Added the column purchase_cost to user's default view

commit fa872b09a9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 12 10:38:31 2022 -0800

    fixes a typo, the world is great again

commit eb67d1b064
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 6 18:00:16 2022 -0600

    Filter items from the report if null returned

commit d0d0058e79
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:19:28 2022 -0800

    removed unwanted changes

commit bbd04f8876
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:13:24 2022 -0800

    adds the rest of the fields for Remote

commit 36901d271b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 5 16:28:19 2022 -0800

    adds csvmatch for remote. Im a bit lost though lol

commit 3206929ee4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Nov 29 09:51:42 2022 -0800

    adds AgeFormatter, not working yet

commit 1fe0bfe17e
Author: snipe <snipe@snipe.net>
Date:   Mon Nov 28 19:27:42 2022 -0800

    Removed extra logging case that was very noisy

    Signed-off-by: snipe <snipe@snipe.net>

commit 8d861cfd82
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:59:18 2022 -0800

    adds age to the asset table

commit 078e7281cd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:45:58 2022 -0800

    adds asset age to asset view

commit 92ae271292
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Nov 9 13:11:33 2022 -0800

    adds validation for department names at Company locations

commit f2d4a61e3c
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:31:37 2022 -0700

    removes dead space

commit 3f25a1bf61
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:25:38 2022 -0700

    removes dead code

commit f9ac447dd1
Merge: 9b448227f b7bcfaccc
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:18:09 2022 -0700

    adds default group to LDAP

commit 9b448227f7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Sep 13 11:40:10 2022 -0700

    tinkering to no avail

commit 28bc97f29f
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Sep 12 11:40:16 2022 -0700

    one line away from this being over with

commit 193b31e427
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 12:58:33 2022 -0700

    select options working, testing sync then done

commit 70ac8af9c4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 09:53:20 2022 -0700

    .

commit 0c362e8b57
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Aug 29 12:09:56 2022 -0700

    gets the groups selector to appear but options are blank

commit fc6fefdb4e
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Aug 25 15:19:38 2022 -0700

    adds migration, variables, checkbox,working on groups

commit 1a908e361e
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Thu Jul 29 10:33:34 2021 +0200

    Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

    locations->isDeletable() checks via gate::allows if a locations is deletable.
    This calls SnipePermissionsPolicy->before() and checks for !Company::isCurrentUserHasAccess($item).
    This returns false because locations don't have a company_id.

    Check for this and return true if the item don't have a company_id.

Signed-off-by: snipe <snipe@snipe.net>
2023-01-09 12:07:46 -08:00
snipe ba51021ce3 Squashed commit of the following:
commit 818db58a7b
Merge: baf14c43e c4f900e9a
Author: snipe <snipe@snipe.net>
Date:   Wed Jan 4 13:22:03 2023 -0800

    Merge pull request #12305 from uberbrady/fix_license_seat_reporting

    Fixed: Change license_seat changing method to properly 'true up' license seats

commit c4f900e9af
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Wed Jan 4 13:02:53 2023 -0800

    Change license_seat changing method to properly 'true up' license seats

commit baf14c43ee
Merge: d187174f0 fa439a192
Author: snipe <snipe@snipe.net>
Date:   Tue Jan 3 14:50:25 2023 -0800

    Merge pull request #12298 from snipe/fixes/db_seeder_company_id

    Fixed db seeder when company id is not present

commit fa439a1928
Author: snipe <snipe@snipe.net>
Date:   Tue Jan 3 14:45:23 2023 -0800

    Check that the array key exists before trying to seed it

    Signed-off-by: snipe <snipe@snipe.net>

commit d187174f00
Merge: 6d3c5e065 92ae27129
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 22 11:29:12 2022 -0800

    Merge pull request #12090 from Godmartinz/deparmtnet_name_validator

    Added: validation for department names at Company locations

commit 6d3c5e0659
Merge: 685cc86d7 e791e6592
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 21 19:04:11 2022 -0800

    Merge pull request #12264 from Godmartinz/gh12253_display_notes_accessories

    Added: notes to the accessories tab for user detail view

commit 685cc86d71
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:24:01 2022 -0800

    Sets the `ldap_default_group` field to nullable and default null

    Signed-off-by: snipe <snipe@snipe.net>

commit fb10a6f218
Merge: 128c21a90 3a9b8a499
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:05:18 2022 -0800

    Merge pull request #12268 from inietov/fixes/people_count

    Fixed: Dashboard user count scoping when full company support is enabled

commit 3a9b8a4993
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 20 18:39:17 2022 -0600

    Calculate the proper amount of people in the dashboard if Full Company Support is enabled

commit 128c21a905
Merge: 88291cadc 75a757d6f
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 15:09:30 2022 -0800

    Merge pull request #12266 from uberbrady/fix-select-all-bug

    Fixed: There was a bug with BS tables' select-all which showed an incorrect list of elements

commit 75a757d6f5
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Tue Dec 20 14:57:58 2022 -0800

    There was a bug with select-all where some bits didn't quite work

commit e791e6592a
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 20 10:37:19 2022 -0800

    adds notes to the accessories tab under users

commit 88291cadc1
Merge: 399c7590c 94afe2bc6
Author: snipe <snipe@snipe.net>
Date:   Mon Dec 19 12:41:32 2022 -0800

    Merge pull request #12254 from akemidx/documentating_something

    Commenting on a scope in Models/Company.php

commit 94afe2bc6a
Author: akemidx <kojotek.dx@gmail.com>
Date:   Mon Dec 19 14:48:43 2022 -0500

    edits & typo fixes

commit 399c7590cd
Merge: d0c5ba70f eb67d1b06
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 14:19:41 2022 -0800

    Merge pull request #12209 from snipe/fixes/error_downloading_unaccepted_assets

    Fixed 500 when downloading the Unaccepted Assets report  [sc-19555]

commit d0c5ba70f6
Merge: 29c2ff56e d9a21cce0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 12:42:29 2022 -0800

    Merge pull request #12242 from inietov/features/add_purchase_cost_column

    Added `purchase_cost` to user's default view [sc-19680]

commit 133d6ffa50
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 15:18:24 2022 -0500

    Commenting on a scope in Models/Company.php

commit d9a21cce00
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Thu Dec 15 14:12:05 2022 -0600

    Add other items' purchase_cost columns to the same permission

commit 29c2ff56ec
Merge: 3e7975b2c 1fe0bfe17
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:26:49 2022 -0800

    Merge pull request #12188 from snipe/fixes/decrease_logging_for_saml_when_not_enabled

    Removed extra logging case that was very noisy

commit 3e7975b2c3
Merge: 227fef76e d870bc3b0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:25:53 2022 -0800

    Merge pull request #12250 from akemidx/grey_out_pw_reset_button

    Fixed: Grey out pw reset button for consistency

commit d870bc3b02
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 14:19:51 2022 -0500

    nested if loop

commit 227fef76ee
Merge: 418ddcfac 9d44720ff
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:06:53 2022 -0800

    Merge pull request #11736 from Godmartinz/gh6508_ldap_default_group

    Adds a permission group selection for directory sync

commit 9d44720ffd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 11:02:34 2022 -0800

    reverted changes to composer.lock

commit 9f3f0a25ed
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:53:45 2022 -0800

    reverted changes to composer.lock

commit 2e228ccb0b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:45:42 2022 -0800

    redid a few things. should be good now :)

commit 3ee413f379
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 09:20:30 2022 -0800

    removes livewire stuff

commit b142f8e012
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Wed Dec 14 23:00:35 2022 -0600

    Add the permission to show purchase cost column to non-admin sessions

commit 418ddcfac3
Merge: c342668f0 1a908e361
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:46:53 2022 -0800

    Merge pull request #9876 from Toreg87/fixes/locations-deletable

    Fixed #9875: Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

commit c342668f0f
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:39 2022 -0800

    Update @scoo73r as a contributor

commit 2f6a26ec7d
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:25 2022 -0800

    Add @scoo73r as a contributor

commit f635278010
Merge: d13a23700 8043b8678
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:42:41 2022 -0800

    Merge pull request #12251 from snipe/security/upgrade_font_awesome

    Upgraded font awesome to 6.2.1

commit 8043b86786
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:41:56 2022 -0800

    Upgraded font awesome to 6.2.1

    Signed-off-by: snipe <snipe@snipe.net>

commit d13a237000
Merge: fabefa61b d0d0058e7
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 12:13:18 2022 -0800

    Merge pull request #12205 from Godmartinz/sc19675_add_remote_to_importer

    Adds remote field to the user importer

commit b114ffd2c3
Author: akemidx <kojotek.dx@gmail.com>
Date:   Wed Dec 14 14:48:59 2022 -0500

    Grey out button pw reset button for consistency

    When user has no email in their profile, the box is greyed out for
    consistency accross all buttons on the user profile

commit fabefa61b0
Merge: 389ec3a3c f3e57d7dc
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 14:00:48 2022 -0800

    Merge pull request #12243 from akemidx/new_grey_out_when_no_assets

    Created method in users.php for adding up all assigned to user and pr…

commit f3e57d7dc0
Author: akemidx <kojotek.dx@gmail.com>
Date:   Tue Dec 13 16:00:59 2022 -0500

    fixing PR

commit 389ec3a3cb
Merge: c432fb9d7 6a72c344b
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 12:57:50 2022 -0800

    Merge pull request #12247 from Godmartinz/gh12225_serial_added_to_components

    adds serial to components tab of assets

commit 6a72c344b7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 12:32:30 2022 -0800

    removed the cuddlers

commit 4442b446b9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 10:30:37 2022 -0800

    adds serial to components tab of assets

commit c432fb9d70
Merge: 9e8fff6e5 fa872b09a
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 10:28:17 2022 -0800

    Merge pull request #12181 from Godmartinz/gh12163_asset_age

    Adds asset age to asset index and asset view pages

commit 07ae91b00f
Author: akemi <akemi@ShibaPro.local>
Date:   Wed Dec 7 17:46:18 2022 -0500

    Created method in users.php for adding up all assigned to user and providing an integer value. this then used to grey out buttons on user view if user has nothing assigned.

commit 450ad3dcec
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Mon Dec 12 14:17:08 2022 -0600

    Added the column purchase_cost to user's default view

commit fa872b09a9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 12 10:38:31 2022 -0800

    fixes a typo, the world is great again

commit eb67d1b064
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 6 18:00:16 2022 -0600

    Filter items from the report if null returned

commit d0d0058e79
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:19:28 2022 -0800

    removed unwanted changes

commit bbd04f8876
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:13:24 2022 -0800

    adds the rest of the fields for Remote

commit 36901d271b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 5 16:28:19 2022 -0800

    adds csvmatch for remote. Im a bit lost though lol

commit 3206929ee4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Nov 29 09:51:42 2022 -0800

    adds AgeFormatter, not working yet

commit 1fe0bfe17e
Author: snipe <snipe@snipe.net>
Date:   Mon Nov 28 19:27:42 2022 -0800

    Removed extra logging case that was very noisy

    Signed-off-by: snipe <snipe@snipe.net>

commit 8d861cfd82
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:59:18 2022 -0800

    adds age to the asset table

commit 078e7281cd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:45:58 2022 -0800

    adds asset age to asset view

commit 92ae271292
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Nov 9 13:11:33 2022 -0800

    adds validation for department names at Company locations

commit f2d4a61e3c
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:31:37 2022 -0700

    removes dead space

commit 3f25a1bf61
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:25:38 2022 -0700

    removes dead code

commit f9ac447dd1
Merge: 9b448227f b7bcfaccc
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:18:09 2022 -0700

    adds default group to LDAP

commit 9b448227f7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Sep 13 11:40:10 2022 -0700

    tinkering to no avail

commit 28bc97f29f
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Sep 12 11:40:16 2022 -0700

    one line away from this being over with

commit 193b31e427
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 12:58:33 2022 -0700

    select options working, testing sync then done

commit 70ac8af9c4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 09:53:20 2022 -0700

    .

commit 0c362e8b57
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Aug 29 12:09:56 2022 -0700

    gets the groups selector to appear but options are blank

commit fc6fefdb4e
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Aug 25 15:19:38 2022 -0700

    adds migration, variables, checkbox,working on groups

commit 1a908e361e
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Thu Jul 29 10:33:34 2021 +0200

    Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

    locations->isDeletable() checks via gate::allows if a locations is deletable.
    This calls SnipePermissionsPolicy->before() and checks for !Company::isCurrentUserHasAccess($item).
    This returns false because locations don't have a company_id.

    Check for this and return true if the item don't have a company_id.

Signed-off-by: snipe <snipe@snipe.net>
2023-01-04 13:53:41 -08:00
snipe a605dc16b6 Set session urls
Signed-off-by: snipe <snipe@snipe.net>
2023-01-02 13:31:52 -08:00
snipe 36858d1c64 Removed whitespace
Signed-off-by: snipe <snipe@snipe.net>
2022-12-21 18:53:48 -08:00
snipe 3d74e40c44 Deleted similar acceptance blades and created one more generic one
Signed-off-by: snipe <snipe@snipe.net>
2022-12-21 18:03:17 -08:00
snipe cc7253b29f Small case/switch refactoring
Signed-off-by: snipe <snipe@snipe.net>
2022-12-21 18:02:34 -08:00
snipe bc185a2848 Squashed commit of the following:
commit 685cc86d71
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:24:01 2022 -0800

    Sets the `ldap_default_group` field to nullable and default null

    Signed-off-by: snipe <snipe@snipe.net>

commit fb10a6f218
Merge: 128c21a90 3a9b8a499
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 17:05:18 2022 -0800

    Merge pull request #12268 from inietov/fixes/people_count

    Fixed: Dashboard user count scoping when full company support is enabled

commit 3a9b8a4993
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 20 18:39:17 2022 -0600

    Calculate the proper amount of people in the dashboard if Full Company Support is enabled

commit 128c21a905
Merge: 88291cadc 75a757d6f
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 20 15:09:30 2022 -0800

    Merge pull request #12266 from uberbrady/fix-select-all-bug

    Fixed: There was a bug with BS tables' select-all which showed an incorrect list of elements

commit 75a757d6f5
Author: Brady Wetherington <bwetherington@grokability.com>
Date:   Tue Dec 20 14:57:58 2022 -0800

    There was a bug with select-all where some bits didn't quite work

commit 88291cadc1
Merge: 399c7590c 94afe2bc6
Author: snipe <snipe@snipe.net>
Date:   Mon Dec 19 12:41:32 2022 -0800

    Merge pull request #12254 from akemidx/documentating_something

    Commenting on a scope in Models/Company.php

commit 94afe2bc6a
Author: akemidx <kojotek.dx@gmail.com>
Date:   Mon Dec 19 14:48:43 2022 -0500

    edits & typo fixes

commit 399c7590cd
Merge: d0c5ba70f eb67d1b06
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 14:19:41 2022 -0800

    Merge pull request #12209 from snipe/fixes/error_downloading_unaccepted_assets

    Fixed 500 when downloading the Unaccepted Assets report  [sc-19555]

commit d0c5ba70f6
Merge: 29c2ff56e d9a21cce0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 12:42:29 2022 -0800

    Merge pull request #12242 from inietov/features/add_purchase_cost_column

    Added `purchase_cost` to user's default view [sc-19680]

commit 133d6ffa50
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 15:18:24 2022 -0500

    Commenting on a scope in Models/Company.php

commit d9a21cce00
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Thu Dec 15 14:12:05 2022 -0600

    Add other items' purchase_cost columns to the same permission

commit 29c2ff56ec
Merge: 3e7975b2c 1fe0bfe17
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:26:49 2022 -0800

    Merge pull request #12188 from snipe/fixes/decrease_logging_for_saml_when_not_enabled

    Removed extra logging case that was very noisy

commit 3e7975b2c3
Merge: 227fef76e d870bc3b0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:25:53 2022 -0800

    Merge pull request #12250 from akemidx/grey_out_pw_reset_button

    Fixed: Grey out pw reset button for consistency

commit d870bc3b02
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 14:19:51 2022 -0500

    nested if loop

commit 227fef76ee
Merge: 418ddcfac 9d44720ff
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:06:53 2022 -0800

    Merge pull request #11736 from Godmartinz/gh6508_ldap_default_group

    Adds a permission group selection for directory sync

commit 9d44720ffd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 11:02:34 2022 -0800

    reverted changes to composer.lock

commit 9f3f0a25ed
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:53:45 2022 -0800

    reverted changes to composer.lock

commit 2e228ccb0b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:45:42 2022 -0800

    redid a few things. should be good now :)

commit 3ee413f379
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 09:20:30 2022 -0800

    removes livewire stuff

commit b142f8e012
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Wed Dec 14 23:00:35 2022 -0600

    Add the permission to show purchase cost column to non-admin sessions

commit 418ddcfac3
Merge: c342668f0 1a908e361
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:46:53 2022 -0800

    Merge pull request #9876 from Toreg87/fixes/locations-deletable

    Fixed #9875: Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

commit c342668f0f
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:39 2022 -0800

    Update @scoo73r as a contributor

commit 2f6a26ec7d
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:25 2022 -0800

    Add @scoo73r as a contributor

commit f635278010
Merge: d13a23700 8043b8678
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:42:41 2022 -0800

    Merge pull request #12251 from snipe/security/upgrade_font_awesome

    Upgraded font awesome to 6.2.1

commit 8043b86786
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:41:56 2022 -0800

    Upgraded font awesome to 6.2.1

    Signed-off-by: snipe <snipe@snipe.net>

commit d13a237000
Merge: fabefa61b d0d0058e7
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 12:13:18 2022 -0800

    Merge pull request #12205 from Godmartinz/sc19675_add_remote_to_importer

    Adds remote field to the user importer

commit b114ffd2c3
Author: akemidx <kojotek.dx@gmail.com>
Date:   Wed Dec 14 14:48:59 2022 -0500

    Grey out button pw reset button for consistency

    When user has no email in their profile, the box is greyed out for
    consistency accross all buttons on the user profile

commit fabefa61b0
Merge: 389ec3a3c f3e57d7dc
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 14:00:48 2022 -0800

    Merge pull request #12243 from akemidx/new_grey_out_when_no_assets

    Created method in users.php for adding up all assigned to user and pr…

commit f3e57d7dc0
Author: akemidx <kojotek.dx@gmail.com>
Date:   Tue Dec 13 16:00:59 2022 -0500

    fixing PR

commit 389ec3a3cb
Merge: c432fb9d7 6a72c344b
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 12:57:50 2022 -0800

    Merge pull request #12247 from Godmartinz/gh12225_serial_added_to_components

    adds serial to components tab of assets

commit 6a72c344b7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 12:32:30 2022 -0800

    removed the cuddlers

commit 4442b446b9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 10:30:37 2022 -0800

    adds serial to components tab of assets

commit c432fb9d70
Merge: 9e8fff6e5 fa872b09a
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 10:28:17 2022 -0800

    Merge pull request #12181 from Godmartinz/gh12163_asset_age

    Adds asset age to asset index and asset view pages

commit 07ae91b00f
Author: akemi <akemi@ShibaPro.local>
Date:   Wed Dec 7 17:46:18 2022 -0500

    Created method in users.php for adding up all assigned to user and providing an integer value. this then used to grey out buttons on user view if user has nothing assigned.

commit 450ad3dcec
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Mon Dec 12 14:17:08 2022 -0600

    Added the column purchase_cost to user's default view

commit fa872b09a9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 12 10:38:31 2022 -0800

    fixes a typo, the world is great again

commit eb67d1b064
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 6 18:00:16 2022 -0600

    Filter items from the report if null returned

commit d0d0058e79
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:19:28 2022 -0800

    removed unwanted changes

commit bbd04f8876
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:13:24 2022 -0800

    adds the rest of the fields for Remote

commit 36901d271b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 5 16:28:19 2022 -0800

    adds csvmatch for remote. Im a bit lost though lol

commit 3206929ee4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Nov 29 09:51:42 2022 -0800

    adds AgeFormatter, not working yet

commit 1fe0bfe17e
Author: snipe <snipe@snipe.net>
Date:   Mon Nov 28 19:27:42 2022 -0800

    Removed extra logging case that was very noisy

    Signed-off-by: snipe <snipe@snipe.net>

commit 8d861cfd82
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:59:18 2022 -0800

    adds age to the asset table

commit 078e7281cd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:45:58 2022 -0800

    adds asset age to asset view

commit f2d4a61e3c
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:31:37 2022 -0700

    removes dead space

commit 3f25a1bf61
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:25:38 2022 -0700

    removes dead code

commit f9ac447dd1
Merge: 9b448227f b7bcfaccc
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:18:09 2022 -0700

    adds default group to LDAP

commit 9b448227f7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Sep 13 11:40:10 2022 -0700

    tinkering to no avail

commit 28bc97f29f
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Sep 12 11:40:16 2022 -0700

    one line away from this being over with

commit 193b31e427
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 12:58:33 2022 -0700

    select options working, testing sync then done

commit 70ac8af9c4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 09:53:20 2022 -0700

    .

commit 0c362e8b57
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Aug 29 12:09:56 2022 -0700

    gets the groups selector to appear but options are blank

commit fc6fefdb4e
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Aug 25 15:19:38 2022 -0700

    adds migration, variables, checkbox,working on groups

commit 1a908e361e
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Thu Jul 29 10:33:34 2021 +0200

    Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

    locations->isDeletable() checks via gate::allows if a locations is deletable.
    This calls SnipePermissionsPolicy->before() and checks for !Company::isCurrentUserHasAccess($item).
    This returns false because locations don't have a company_id.

    Check for this and return true if the item don't have a company_id.

Signed-off-by: snipe <snipe@snipe.net>
2022-12-21 16:46:29 -08:00
snipe d33829f67a New universal accept blade
Signed-off-by: snipe <snipe@snipe.net>
2022-12-20 15:11:12 -08:00
snipe d818dc19c1 Felt cute, might revert later
Signed-off-by: snipe <snipe@snipe.net>
2022-12-20 15:11:02 -08:00
snipe d6769443a9 Squashed commit of the following:
commit 399c7590cd
Merge: d0c5ba70f eb67d1b06
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 14:19:41 2022 -0800

    Merge pull request #12209 from snipe/fixes/error_downloading_unaccepted_assets

    Fixed 500 when downloading the Unaccepted Assets report  [sc-19555]

commit d0c5ba70f6
Merge: 29c2ff56e d9a21cce0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 12:42:29 2022 -0800

    Merge pull request #12242 from inietov/features/add_purchase_cost_column

    Added `purchase_cost` to user's default view [sc-19680]

commit d9a21cce00
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Thu Dec 15 14:12:05 2022 -0600

    Add other items' purchase_cost columns to the same permission

commit 29c2ff56ec
Merge: 3e7975b2c 1fe0bfe17
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:26:49 2022 -0800

    Merge pull request #12188 from snipe/fixes/decrease_logging_for_saml_when_not_enabled

    Removed extra logging case that was very noisy

commit 3e7975b2c3
Merge: 227fef76e d870bc3b0
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:25:53 2022 -0800

    Merge pull request #12250 from akemidx/grey_out_pw_reset_button

    Fixed: Grey out pw reset button for consistency

commit d870bc3b02
Author: akemidx <kojotek.dx@gmail.com>
Date:   Thu Dec 15 14:19:51 2022 -0500

    nested if loop

commit 227fef76ee
Merge: 418ddcfac 9d44720ff
Author: snipe <snipe@snipe.net>
Date:   Thu Dec 15 11:06:53 2022 -0800

    Merge pull request #11736 from Godmartinz/gh6508_ldap_default_group

    Adds a permission group selection for directory sync

commit 9d44720ffd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 11:02:34 2022 -0800

    reverted changes to composer.lock

commit 9f3f0a25ed
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:53:45 2022 -0800

    reverted changes to composer.lock

commit 2e228ccb0b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 10:45:42 2022 -0800

    redid a few things. should be good now :)

commit 3ee413f379
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Dec 15 09:20:30 2022 -0800

    removes livewire stuff

commit b142f8e012
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Wed Dec 14 23:00:35 2022 -0600

    Add the permission to show purchase cost column to non-admin sessions

commit 418ddcfac3
Merge: c342668f0 1a908e361
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:46:53 2022 -0800

    Merge pull request #9876 from Toreg87/fixes/locations-deletable

    Fixed #9875: Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

commit c342668f0f
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:39 2022 -0800

    Update @scoo73r as a contributor

commit 2f6a26ec7d
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 17:25:25 2022 -0800

    Add @scoo73r as a contributor

commit f635278010
Merge: d13a23700 8043b8678
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:42:41 2022 -0800

    Merge pull request #12251 from snipe/security/upgrade_font_awesome

    Upgraded font awesome to 6.2.1

commit 8043b86786
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 16:41:56 2022 -0800

    Upgraded font awesome to 6.2.1

    Signed-off-by: snipe <snipe@snipe.net>

commit d13a237000
Merge: fabefa61b d0d0058e7
Author: snipe <snipe@snipe.net>
Date:   Wed Dec 14 12:13:18 2022 -0800

    Merge pull request #12205 from Godmartinz/sc19675_add_remote_to_importer

    Adds remote field to the user importer

commit b114ffd2c3
Author: akemidx <kojotek.dx@gmail.com>
Date:   Wed Dec 14 14:48:59 2022 -0500

    Grey out button pw reset button for consistency

    When user has no email in their profile, the box is greyed out for
    consistency accross all buttons on the user profile

commit fabefa61b0
Merge: 389ec3a3c f3e57d7dc
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 14:00:48 2022 -0800

    Merge pull request #12243 from akemidx/new_grey_out_when_no_assets

    Created method in users.php for adding up all assigned to user and pr…

commit f3e57d7dc0
Author: akemidx <kojotek.dx@gmail.com>
Date:   Tue Dec 13 16:00:59 2022 -0500

    fixing PR

commit 389ec3a3cb
Merge: c432fb9d7 6a72c344b
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 12:57:50 2022 -0800

    Merge pull request #12247 from Godmartinz/gh12225_serial_added_to_components

    adds serial to components tab of assets

commit 6a72c344b7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 12:32:30 2022 -0800

    removed the cuddlers

commit 4442b446b9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 13 10:30:37 2022 -0800

    adds serial to components tab of assets

commit c432fb9d70
Merge: 9e8fff6e5 fa872b09a
Author: snipe <snipe@snipe.net>
Date:   Tue Dec 13 10:28:17 2022 -0800

    Merge pull request #12181 from Godmartinz/gh12163_asset_age

    Adds asset age to asset index and asset view pages

commit 07ae91b00f
Author: akemi <akemi@ShibaPro.local>
Date:   Wed Dec 7 17:46:18 2022 -0500

    Created method in users.php for adding up all assigned to user and providing an integer value. this then used to grey out buttons on user view if user has nothing assigned.

commit 450ad3dcec
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Mon Dec 12 14:17:08 2022 -0600

    Added the column purchase_cost to user's default view

commit fa872b09a9
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 12 10:38:31 2022 -0800

    fixes a typo, the world is great again

commit eb67d1b064
Author: Ivan Nieto Vivanco <inietov@gmail.com>
Date:   Tue Dec 6 18:00:16 2022 -0600

    Filter items from the report if null returned

commit d0d0058e79
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:19:28 2022 -0800

    removed unwanted changes

commit bbd04f8876
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Dec 6 11:13:24 2022 -0800

    adds the rest of the fields for Remote

commit 36901d271b
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Dec 5 16:28:19 2022 -0800

    adds csvmatch for remote. Im a bit lost though lol

commit 3206929ee4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Nov 29 09:51:42 2022 -0800

    adds AgeFormatter, not working yet

commit 1fe0bfe17e
Author: snipe <snipe@snipe.net>
Date:   Mon Nov 28 19:27:42 2022 -0800

    Removed extra logging case that was very noisy

    Signed-off-by: snipe <snipe@snipe.net>

commit 8d861cfd82
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:59:18 2022 -0800

    adds age to the asset table

commit 078e7281cd
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Nov 28 10:45:58 2022 -0800

    adds asset age to asset view

commit f2d4a61e3c
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:31:37 2022 -0700

    removes dead space

commit 3f25a1bf61
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:25:38 2022 -0700

    removes dead code

commit f9ac447dd1
Merge: 9b448227f b7bcfaccc
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Oct 18 15:18:09 2022 -0700

    adds default group to LDAP

commit 9b448227f7
Author: Godfrey M <godmartinz@gmail.com>
Date:   Tue Sep 13 11:40:10 2022 -0700

    tinkering to no avail

commit 28bc97f29f
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Sep 12 11:40:16 2022 -0700

    one line away from this being over with

commit 193b31e427
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 12:58:33 2022 -0700

    select options working, testing sync then done

commit 70ac8af9c4
Author: Godfrey M <godmartinz@gmail.com>
Date:   Wed Aug 31 09:53:20 2022 -0700

    .

commit 0c362e8b57
Author: Godfrey M <godmartinz@gmail.com>
Date:   Mon Aug 29 12:09:56 2022 -0700

    gets the groups selector to appear but options are blank

commit fc6fefdb4e
Author: Godfrey M <godmartinz@gmail.com>
Date:   Thu Aug 25 15:19:38 2022 -0700

    adds migration, variables, checkbox,working on groups

commit 1a908e361e
Author: Tobias Regnery <tobias.regnery@gmail.com>
Date:   Thu Jul 29 10:33:34 2021 +0200

    Make locations deletable for non Superuser-Accounts with FullMultipleCompanySupport

    locations->isDeletable() checks via gate::allows if a locations is deletable.
    This calls SnipePermissionsPolicy->before() and checks for !Company::isCurrentUserHasAccess($item).
    This returns false because locations don't have a company_id.

    Check for this and return true if the item don't have a company_id.

Signed-off-by: snipe <snipe@snipe.net>
2022-12-15 15:18:16 -08:00
snipe 9e0566ca7a First stab
Signed-off-by: snipe <snipe@snipe.net>
2022-12-09 16:38:40 -08:00
1843 changed files with 298674 additions and 25172 deletions
-61
View File
@@ -2828,67 +2828,6 @@
"contributions": [
"code"
]
},
{
"login": "subdriven",
"name": "subdriven",
"avatar_url": "https://avatars.githubusercontent.com/u/5957345?v=4",
"profile": "https://github.com/subdriven",
"contributions": [
"code"
]
},
{
"login": "AndrewSav",
"name": "Andrew Savinykh",
"avatar_url": "https://avatars.githubusercontent.com/u/658865?v=4",
"profile": "https://github.com/AndrewSav",
"contributions": [
"code"
]
},
{
"login": "kenchan0130",
"name": "Tadayuki Onishi",
"avatar_url": "https://avatars.githubusercontent.com/u/1155067?v=4",
"profile": "https://kenchan0130.github.io",
"contributions": [
"code"
]
},
{
"login": "floschoepfer",
"name": "Florian",
"avatar_url": "https://avatars.githubusercontent.com/u/112496896?v=4",
"profile": "https://github.com/floschoepfer",
"contributions": [
"code"
]
},
{
"login": "spencerrlongg",
"name": "Spencer Long",
"avatar_url": "https://avatars.githubusercontent.com/u/7305753?v=4",
"profile": "http://spencerlong.com",
"contributions": [
"code"
]
},
{
"login": "marcusmoore",
"name": "Marcus Moore",
"avatar_url": "https://avatars.githubusercontent.com/u/1141514?v=4",
"profile": "https://github.com/marcusmoore",
"contributions": [
"code"
]
},
{
"login": "Mezzle",
"name": "Martin Meredith",
"avatar_url": "https://avatars.githubusercontent.com/u/570639?v=4",
"profile": "https://github.com/Mezzle",
"contributions": []
}
]
}
+5 -5
View File
@@ -20,13 +20,13 @@ PUBLIC_FILESYSTEM_DISK=local_public
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=null
DB_USERNAME=null
DB_PASSWORD=null
DB_DATABASE=snipeit-local
DB_USERNAME=snipeit-local
DB_PASSWORD=snipeit-local
DB_PREFIX=null
#DB_DUMP_PATH=
DB_DUMP_PATH='/Applications/MAMP/Library/bin'
# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS
+75
View File
@@ -0,0 +1,75 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing
APP_DEBUG=true
APP_KEY=base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU=
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_PORT=3306
DB_DATABASE=testing.sqlite
DB_USERNAME=null
DB_PASSWORD=null
# --------------------------------------------
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
# --------------------------------------------
MAIL_DRIVER=log
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 SETTINGS
# --------------------------------------------
AWS_SECRET_ACCESS_KEY=null
AWS_ACCESS_KEY_ID=null
AWS_DEFAULT_REGION=null
AWS_BUCKET=null
AWS_BUCKET_ROOT=null
AWS_URL=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
# --------------------------------------------
LOG_CHANNEL=single
LOG_LEVEL=debug
-19
View File
@@ -1,19 +0,0 @@
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing
APP_DEBUG=true
APP_KEY=base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU=
APP_URL=http://localhost:8000
APP_TIMEZONE='UTC'
APP_LOCALE=en
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=null
DB_USERNAME=null
DB_PASSWORD=null
@@ -2,6 +2,8 @@ name: Feature Request
description: Suggest an idea for this project
title: "[Feature Request]: "
labels: ["feature request"]
assignees:
- snipe
body:
- type: textarea
attributes:
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
language: [ 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.1.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+2 -2
View File
@@ -32,11 +32,11 @@ jobs:
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.1.0
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@v4.3.0
uses: codacy/codacy-analysis-cli-action@v4.2.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
-21
View File
@@ -1,21 +0,0 @@
name: Crowdin Action
on:
push:
branches: [ develop ]
jobs:
upload-sources-to-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Crowdin push
uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: false
download_translations: false
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.1.0
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
@@ -72,7 +72,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v4
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile.alpine
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.1.0
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
@@ -72,7 +72,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v4
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
-4
View File
@@ -1,10 +1,6 @@
.couscous
.DS_Store
.env
.env.dusk.*
!.env.dusk.example
.env.testing
phpstan.neon
.idea
/bin/
/bootstrap/compiled.php
+3 -8
View File
@@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-318-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-311-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@@ -60,17 +60,13 @@ Since the release of the JSON REST API, several third-party developers have been
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
- [jamf-snipe-rename](https://macblog.org/jamf-snipe-rename/) - Python script to rename computers in Jamf from Snipe-IT
- [Marksman](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@RodneyLeeBrands](https://github.com/RodneyLeeBrands) - Python script to synchronize information between Mosyle and Snipe-IT
- [WWW::SnipeIT](https://github.com/SEDC/perl-www-snipeit) by [@SEDC](https://github.com/SEDC) - perl module for accessing the API
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
@@ -143,8 +139,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") | [<img src="https://avatars.githubusercontent.com/u/7991086?v=4" width="110px;"/><br /><sub>Daniel Reeder</sub>](https://github.com/reederda)<br />[🌍](#translation-reederda "Translation") [🌍](#translation-reederda "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=reederda "Code") | [<img src="https://avatars.githubusercontent.com/u/109422491?v=4" width="110px;"/><br /><sub>vickyjaura183</sub>](https://github.com/vickyjaura183)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vickyjaura183 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/32363424?v=4" width="110px;"/><br /><sub>Peace</sub>](https://github.com/julian-piehl)<br />[💻](https://github.com/snipe/snipe-it/commits?author=julian-piehl "Code") | [<img src="https://avatars.githubusercontent.com/u/231528?v=4" width="110px;"/><br /><sub>Kyle Gordon</sub>](https://github.com/kylegordon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kylegordon "Code") | [<img src="https://avatars.githubusercontent.com/u/53009155?v=4" width="110px;"/><br /><sub>Katharina Drexel</sub>](http://www.bfh.ch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sunflowerbofh "Code") | [<img src="https://avatars.githubusercontent.com/u/1931963?v=4" width="110px;"/><br /><sub>David Sferruzza</sub>](https://david.sferruzza.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dsferruzza "Code") | [<img src="https://avatars.githubusercontent.com/u/19511639?v=4" width="110px;"/><br /><sub>Rick Nelson</sub>](https://github.com/rnelsonee)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rnelsonee "Code") | [<img src="https://avatars.githubusercontent.com/u/94169344?v=4" width="110px;"/><br /><sub>BasO12</sub>](https://github.com/BasO12)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BasO12 "Code") | [<img src="https://avatars.githubusercontent.com/u/111710123?v=4" width="110px;"/><br /><sub>Vautia</sub>](https://github.com/Vautia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Vautia "Code") |
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") |
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") | [<img src="https://avatars.githubusercontent.com/u/658865?v=4" width="110px;"/><br /><sub>Andrew Savinykh</sub>](https://github.com/AndrewSav)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AndrewSav "Code") | [<img src="https://avatars.githubusercontent.com/u/1155067?v=4" width="110px;"/><br /><sub>Tadayuki Onishi</sub>](https://kenchan0130.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kenchan0130 "Code") | [<img src="https://avatars.githubusercontent.com/u/112496896?v=4" width="110px;"/><br /><sub>Florian</sub>](https://github.com/floschoepfer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=floschoepfer "Code") |
| [<img src="https://avatars.githubusercontent.com/u/7305753?v=4" width="110px;"/><br /><sub>Spencer Long</sub>](http://spencerlong.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=spencerrlongg "Code") | [<img src="https://avatars.githubusercontent.com/u/1141514?v=4" width="110px;"/><br /><sub>Marcus Moore</sub>](https://github.com/marcusmoore)<br />[💻](https://github.com/snipe/snipe-it/commits?author=marcusmoore "Code") | [<img src="https://avatars.githubusercontent.com/u/570639?v=4" width="110px;"/><br /><sub>Martin Meredith</sub>](https://github.com/Mezzle)<br /> |
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
+43 -29
View File
@@ -1,51 +1,65 @@
# Running the Test Suite
# Using the Test Suite
This document is targeted at developers looking to make modifications to this application's code base and want to run the existing test suite.
This document is targeted at developers looking to make modifications to
this application's code base and want to run the existing test suite.
Before starting, follow the [instructions](README.md#installation) for installing the application locally and ensure you can load it in a browser properly.
## Unit and Feature Tests
## Setup
Before attempting to run the test suite copy the example environment file for tests and update the values to match your environment:
Follow the instructions for installing the application locally,
making sure to have also run the [database migrations](link to db migrations).
`cp .env.testing.example .env.testing`
> Since the data in the database is flushed after each test it is recommended you create a separate mysql database for specifically for tests
Now you are ready to run the entire test suite from your terminal:
## Unit Tests
`php artisan test`
The application will use values in the `.env.testing` file located
in the root directory to override the
default settings and/or other values that exist in your `.env` files.
To run individual test files, you can pass the path to the test that you want to run:
Make sure to modify the section in `.env.testing` that has the
database settings. In the example below, it is connecting to the
[MariaDB](link-to-maria-db) server that is used if you install the
application using [Docker](https://docker.com).
`php artisan test tests/Unit/AccessoryTest.php`
```dotenv
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=snipeit
DB_USERNAME=root
DB_PASSWORD=changeme1234
```
To run the entire unit test suite, use the following command from your terminal:
`php artisan test --env=testing`
To run individual test files, you can pass the path to the test that
you want to run.
`php artisan test --env=testing tests/Unit/AccessoryTest.php`
## Browser Tests
Browser tests are run via [Laravel Dusk](https://laravel.com/docs/8.x/dusk) and require Google Chrome to be installed.
The browser tests use [Dusk](https://laravel.com/docs/8.x/dusk) to run them.
When troubleshooting any problems, make sure that your `.env` file is configured
correctly to run the existing application.
Before attempting to run Dusk tests copy the example environment file for Dusk and update the values to match your environment:
### Test Setup
`cp .env.dusk.example .env.dusk.local`
> `local` refers to the value of `APP_ENV` in your `.env` so if you have it set to `dev` then the file should be named `.env.dusk.dev`.
**Important**: Dusk tests cannot be run using an in-memory SQLite database. Additionally, the Dusk test suite uses the `DatabaseMigrations` trait which will leave the database in a fresh state after running. Therefore, it is recommended that you create a test database and point `DB_DATABASE` in `.env.dusk.local` to it.
### Running Browser Tests
Your application needs to be configured and up and running in order for the browser tests to actually run. When running the tests locally, you can start the application using the following command:
Your application needs to be configued and up and running in order for the browser
tests to actually run. When running the tests locally, you can start the application
using the following command:
`php artisan serve`
Now you are ready to run the test suite. Use the following command from another terminal tab or window:
To run the test suite use the following command from another terminal tab or window:
`php artisan dusk`
To run individual test files, you can pass the path to the test that you want to run:
To run individual test files, you can pass the path to the test that you want to run.
`php artisan dusk tests/Browser/LoginTest.php`
If you get an error when attempting to run Dusk tests that says `Couldn't connect to server` run:
`php artisan dusk:chrome-driver --detect`
This command will install the specific ChromeDriver Dusk needs for your operating system and Chrome version.
@@ -56,7 +56,7 @@ class CheckoutLicenseToAllUsers extends Command
return false;
}
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '==', 1)->with('licenses')->get();
$users = User::whereNull('deleted_at')->with('licenses')->get();
if ($users->count() > $license->getAvailSeatsCountAttribute()) {
$this->info('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
+9 -20
View File
@@ -3,29 +3,14 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use \App\Models\User;
class CreateAdmin extends Command
{
/** @mixin User **/
/**
* App\Console\CreateAdmin
* @property mixed $first_name
* @property string $last_name
* @property string $username
* @property string $email
* @property string $permissions
* @property string $password
* @property boolean $activated
* @property boolean $show_in_list
* @property \Illuminate\Support\Carbon|null $created_at
* @property mixed $created_by
* 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?}';
/**
@@ -45,7 +30,11 @@ class CreateAdmin extends Command
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$first_name = $this->option('first_name');
@@ -58,7 +47,7 @@ class CreateAdmin extends Command
if (($first_name == '') || ($last_name == '') || ($username == '') || ($email == '') || ($password == '')) {
$this->info('ERROR: All fields are required.');
} else {
$user = new User;
$user = new \App\Models\User;
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $username;
+39 -52
View File
@@ -44,18 +44,12 @@ class LdapSync extends Command
*/
public function handle()
{
// If LDAP enabled isn't set to 1 (ldap_enabled!=1) then we should cut this short immediately without going any further
if (Setting::getSettings()->ldap_enabled!='1') {
$this->error('LDAP is not enabled. Aborting. See Settings > LDAP to enable it.');
exit();
}
ini_set('max_execution_time', env('LDAP_TIME_LIM', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('LDAP_MEM_LIM', '500M'));
$ldap_result_username = Setting::getSettings()->ldap_username_field;
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
$ldap_result_active_flag = Setting::getSettings()->ldap_active_flag;
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
$ldap_result_email = Setting::getSettings()->ldap_email;
@@ -74,7 +68,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
Log::info($e);
LOG::info($e);
return [];
}
@@ -84,7 +78,7 @@ class LdapSync extends Command
try {
if ($this->option('base_dn') != '') {
$search_base = $this->option('base_dn');
Log::debug('Importing users from specified base DN: \"'.$search_base.'\".');
LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
} else {
$search_base = null;
}
@@ -98,7 +92,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
Log::info($e);
LOG::info($e);
return [];
}
@@ -108,16 +102,16 @@ class LdapSync extends Command
if ($this->option('location') != '') {
$location = Location::where('name', '=', $this->option('location'))->first();
Log::debug('Location name '.$this->option('location').' passed');
Log::debug('Importing to '.$location->name.' ('.$location->id.')');
LOG::debug('Location name '.$this->option('location').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
} elseif ($this->option('location_id') != '') {
$location = Location::where('id', '=', $this->option('location_id'))->first();
Log::debug('Location ID '.$this->option('location_id').' passed');
Log::debug('Importing to '.$location->name.' ('.$location->id.')');
LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
}
if (! isset($location)) {
Log::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
}
/* Process locations with explicitly defined OUs, if doing a full import. */
@@ -133,7 +127,7 @@ class LdapSync extends Command
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (count($ldap_ou_locations) > 0) {
Log::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
@@ -151,7 +145,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => trans('admin/users/message.error.ldap_could_not_search').' Location: '.$ldap_loc['name'].' (ID: '.$ldap_loc['id'].') cannot connect to "'.$ldap_loc['ldap_ou'].'" - '.$e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
Log::info($e);
LOG::info($e);
return [];
}
@@ -185,30 +179,20 @@ class LdapSync extends Command
$manager_cache = [];
if($ldap_default_group != null) {
$default = Group::find($ldap_default_group);
if (!$default) {
$ldap_default_group = null; // un-set the default group if that group doesn't exist
}
}
for ($i = 0; $i < $results['count']; $i++) {
$item = [];
$item['username'] = $results[$i][$ldap_result_username][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_result_emp_num][0] ?? '';
$item['lastname'] = $results[$i][$ldap_result_last_name][0] ?? '';
$item['firstname'] = $results[$i][$ldap_result_first_name][0] ?? '';
$item['email'] = $results[$i][$ldap_result_email][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_result_phone][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_result_jobtitle][0] ?? '';
$item['country'] = $results[$i][$ldap_result_country][0] ?? '';
$item['department'] = $results[$i][$ldap_result_dept][0] ?? '';
$item['manager'] = $results[$i][$ldap_result_manager][0] ?? '';
$item['username'] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : '';
$item['employee_number'] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : '';
$item['lastname'] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : '';
$item['firstname'] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : '';
$item['email'] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : '';
$item['ldap_location_override'] = isset($results[$i]['ldap_location_override']) ? $results[$i]['ldap_location_override'] : '';
$item['location_id'] = isset($results[$i]['location_id']) ? $results[$i]['location_id'] : '';
$item['telephone'] = isset($results[$i][$ldap_result_phone][0]) ? $results[$i][$ldap_result_phone][0] : '';
$item['jobtitle'] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : '';
$item['country'] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : '';
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
$item['manager'] = isset($results[$i][$ldap_result_manager][0]) ? $results[$i][$ldap_result_manager][0] : '';
$department = Department::firstOrCreate([
@@ -237,6 +221,13 @@ class LdapSync extends Command
$user->country = $item['country'];
$user->department_id = $department->id;
if($ldap_default_group != null) {
$default = Group::select()->where('id', $ldap_default_group)->first();
$user->permissions = $default->permissions;
}
if($item['manager'] != null) {
// Check Cache first
if (isset($manager_cache[$item['manager']])) {
@@ -309,18 +300,17 @@ class LdapSync extends Command
$user->activated = 0;
} */
$enabled_accounts = [
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
'66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD
'262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'4194816',// 0x400200 NORMAL_ACCOUNT, DONT_REQ_PREAUTH
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
'66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD
'262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'4194816',// 0x400200 NORMAL_ACCOUNT, DONT_REQ_PREAUTH
'4260352', // 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
'1049088', // 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
'1114624', // 0x110200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, NOT_DELEGATED,
];
$user->activated = (in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts)) ? 1 : 0;
@@ -346,9 +336,6 @@ class LdapSync extends Command
if ($user->save()) {
$item['note'] = $item['createorupdate'];
$item['status'] = 'success';
if ( $item['createorupdate'] === 'created' && $ldap_default_group) {
$user->groups()->attach($ldap_default_group);
}
} else {
foreach ($user->getErrors()->getMessages() as $key => $err) {
@@ -1,52 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\User;
class NormalizeUserNames extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:normalize-names';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Normalizes weirdly formatted names as first-letter upercased';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$users = User::get();
$this->info($users->count() . ' users');
foreach ($users as $user) {
$user->first_name = ucwords(strtolower($user->first_name));
$user->last_name = ucwords(strtolower($user->last_name));
$user->email = strtolower($user->email);
$user->save();
}
}
}
+2 -2
View File
@@ -149,7 +149,7 @@ class RestoreFromBackup extends Command
$boring_files[] = $raw_path;
continue;
}
if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') {
if (@pathinfo($raw_path)['extension'] == 'sql') {
\Log::debug("Found a sql file!");
$sqlfiles[] = $raw_path;
$sqlfile_indices[] = $i;
@@ -214,7 +214,7 @@ class RestoreFromBackup extends Command
$env_vars['MYSQL_PWD'] = config('database.connections.mysql.password');
// TODO notes: we are stealing the dump_binary_path (which *probably* also has your copy of the mysql binary in it. But it might not, so we might need to extend this)
// we unilaterally prepend a slash to the `mysql` command. This might mean your path could look like /blah/blah/blah//mysql - which should be fine. But maybe in some environments it isn't?
$mysql_binary = config('database.connections.mysql.dump.dump_binary_path').\DIRECTORY_SEPARATOR.'mysql'.(\DIRECTORY_SEPARATOR == '\\' ? ".exe" : "");
$mysql_binary = config('database.connections.mysql.dump.dump_binary_path').'/mysql';
if( ! file_exists($mysql_binary) ) {
return $this->error("mysql tool at: '$mysql_binary' does not exist, cannot restore. Please edit DB_DUMP_PATH in your .env to point to a directory that contains the mysqldump and mysql binary");
}
-24
View File
@@ -1,24 +0,0 @@
<?php
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
class UserMerged
{
use Dispatchable, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(User $from_user, User $to_user, User $admin)
{
$this->merged_from = $from_user;
$this->merged_to = $to_user;
$this->admin = $admin;
}
}
+4 -11
View File
@@ -6,7 +6,6 @@ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Helpers\Helper;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException;
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
use Log;
use Throwable;
use JsonException;
@@ -29,7 +28,6 @@ class Handler extends ExceptionHandler
\Intervention\Image\Exception\NotSupportedException::class,
\League\OAuth2\Server\Exception\OAuthServerException::class,
JsonException::class,
SCIMException::class, //these generally don't need to be reported
];
/**
@@ -43,9 +41,7 @@ class Handler extends ExceptionHandler
public function report(Throwable $exception)
{
if ($this->shouldReport($exception)) {
if (class_exists(\Log::class)) {
\Log::error($exception);
}
\Log::error($exception);
return parent::report($exception);
}
}
@@ -55,7 +51,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
* @return \Illuminate\Http\Response
*/
public function render($request, Throwable $e)
{
@@ -72,9 +68,6 @@ class Handler extends ExceptionHandler
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422);
}
if ($e instanceof SCIMException) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid SCIM Request'), 400);
}
// Handle Ajax requests that fail because the model doesn't exist
if ($request->ajax() || $request->wantsJson()) {
@@ -118,8 +111,8 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
+24 -101
View File
@@ -334,11 +334,7 @@ class Helper
'#92896B',
];
$total_colors = count($colors);
if ($index >= $total_colors) {
$index = $index - $total_colors;
}
return $colors[$index];
}
@@ -532,23 +528,20 @@ class Helper
* @since [v2.5]
* @return array
*/
public static function categoryTypeList($selection=null)
public static function categoryTypeList()
{
$category_types = [
'' => '',
'accessory' => trans('general.accessory'),
'asset' => trans('general.asset'),
'consumable' => trans('general.consumable'),
'component' => trans('general.component'),
'license' => trans('general.license'),
'accessory' => 'Accessory',
'asset' => 'Asset',
'consumable' => 'Consumable',
'component' => 'Component',
'license' => 'License',
];
if($selection != null){
return $category_types[$selection];
}
else
return $category_types;
}
/**
* Get the list of custom fields in an array to make a dropdown menu
*
@@ -1099,15 +1092,6 @@ class Helper
return $file_name;
}
/**
* Universal helper to show file size in human-readable formats
*
* @author A. Gianotto <snipe@snipe.net>
* @since 5.0
*
* @return string[]
*/
public static function formatFilesizeUnits($bytes)
{
if ($bytes >= 1073741824)
@@ -1137,91 +1121,30 @@ class Helper
return $bytes;
}
/**
* This is weird but used by the side nav to determine which URL to point the user to
*
* @author A. Gianotto <snipe@snipe.net>
* @since 5.0
*
* @return string[]
*/
public static function SettingUrls(){
$settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index'];
return $settings;
}
/**
* Generic helper (largely used by livewire right now) that returns the font-awesome icon
* for the object type.
*
* @author A. Gianotto <snipe@snipe.net>
* @since 6.1.0
*
* @return string
*/
public static function iconTypeByItem($item) {
switch ($item) {
case 'asset':
return 'fas fa-barcode';
break;
case 'accessory':
return 'fas fa-keyboard';
break;
case 'component':
return 'fas fa-hdd';
break;
case 'consumable':
return 'fas fa-tint';
break;
case 'license':
return 'far fa-save';
break;
case 'location':
return 'fas fa-map-marker-alt';
break;
case 'user':
return 'fas fa-user';
break;
public static function AgeFormat($date) {
$year = Carbon::parse($date)
->diff(now())->y;
$month = Carbon::parse($date)
->diff(now())->m;
$days = Carbon::parse($date)
->diff(now())->d;
$age='';
if ($year) {
$age .= $year.'y ';
}
if ($month) {
$age .= $month.'m ';
}
if ($days) {
$age .= $days.'d';
}
}
return $age;
/*
* This is a shorter way to see if the app is in demo mode.
*
* This makes it cleanly available in blades and in controllers, e.g.
*
* Blade:
* {{ Helper::isDemoMode() ? ' disabled' : ''}} for form blades where we need to disable a form
*
* Controller:
* if (Helper::isDemoMode()) {
* // don't allow the thing
* }
* @todo - use this everywhere else in the app where we have very long if/else config('app.lock_passwords') stuff
*/
public static function isDemoMode() {
if (config('app.lock_passwords') === true) {
return true;
\Log::debug('app locked!');
}
return false;
}
/*
* I know it's gauche to return a shitty HTML string, but this is just a helper and since it will be the same every single time,
* it seemed pretty safe to do here. Don't you judge me.
*/
public static function showDemoModeFieldWarning() {
if (Helper::isDemoMode()) {
return "<p class=\"text-warning\"><i class=\"fas fa-lock\"></i>" . trans('general.feature_disabled') . "</p>";
}
}
}
@@ -63,7 +63,6 @@ class AccessoriesController extends Controller
public function store(ImageUploadRequest $request)
{
$this->authorize(Accessory::class);
// create a new model instance
$accessory = new Accessory();
@@ -83,6 +82,7 @@ class AccessoriesController extends Controller
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory created?
@@ -115,33 +115,6 @@ class AccessoriesController extends Controller
}
/**
* Returns a view that presents a form to clone an accessory.
*
* @author [J. Vinsmoke]
* @param int $accessoryId
* @since [v6.0]
* @return View
*/
public function getClone($accessoryId = null)
{
$this->authorize('create', Accesory::class);
// Check if the asset exists
if (is_null($accessory_to_clone = Accessory::find($accessoryId))) {
// Redirect to the asset management page
return redirect()->route('accessory.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$accessory = clone $accessory_to_clone;
$accessory->id = null;
$accessory->location_id = null;
return view('accessories/edit')
->with('item', $accessory);
}
/**
* Save edited Accessory from form post
@@ -154,47 +127,45 @@ class AccessoriesController extends Controller
*/
public function update(ImageUploadRequest $request, $accessoryId = null)
{
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
$this->authorize($accessory);
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$accessory->users_count"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
// Update the accessory data
$accessory->name = request('name');
$accessory->location_id = request('location_id');
$accessory->min_amt = request('min_amt');
$accessory->category_id = request('category_id');
$accessory->company_id = Company::getIdForCurrentUser(request('company_id'));
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory updated?
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
} else {
if (is_null($accessory = Accessory::find($accessoryId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$min = $accessory->numCheckedOut();
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$min"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$this->authorize($accessory);
// Update the accessory data
$accessory->name = request('name');
$accessory->location_id = request('location_id');
$accessory->min_amt = request('min_amt');
$accessory->category_id = request('category_id');
$accessory->company_id = Company::getIdForCurrentUser(request('company_id'));
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory updated?
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
@@ -246,7 +217,7 @@ class AccessoriesController extends Controller
*/
public function show($accessoryID = null)
{
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
$accessory = Accessory::find($accessoryID);
$this->authorize('view', $accessory);
if (isset($accessory->id)) {
return view('accessories/view', compact('accessory'));
@@ -25,16 +25,11 @@ class AccessoryCheckoutController extends Controller
public function create($accessoryId)
{
// Check if the accessory exists
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
}
// Make sure there is at least one available to checkout
if ($accessory->numRemaining() <= 0){
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
}
if ($accessory->category) {
$this->authorize('checkout', $accessory);
@@ -60,23 +55,17 @@ class AccessoryCheckoutController extends Controller
public function store(Request $request, $accessoryId)
{
// Check if the accessory exists
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
if (is_null($accessory = Accessory::find($accessoryId))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.user_not_found'));
}
$this->authorize('checkout', $accessory);
if (!$user = User::find($request->input('assigned_to'))) {
if (! $user = User::find($request->input('assigned_to'))) {
return redirect()->route('accessories.checkout.show', $accessory->id)->with('error', trans('admin/accessories/message.checkout.user_does_not_exist'));
}
// Make sure there is at least one available to checkout
if ($accessory->numRemaining() <= 0){
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
}
// Update the accessory data
$accessory->assigned_to = e($request->input('assigned_to'));
@@ -113,8 +113,6 @@ class AcceptanceController extends Controller
Storage::makeDirectory('private_uploads/signatures', 775);
}
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
$display_model = '';
$pdf_view_route = '';
@@ -140,6 +138,7 @@ class AcceptanceController extends Controller
// The item was accepted, check for a signature
if ($request->filled('signature_output')) {
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
$data_uri = $request->input('signature_output');
$encoded_image = explode(',', $data_uri);
@@ -151,59 +150,42 @@ class AcceptanceController extends Controller
} else {
return redirect()->back()->with('error', trans('general.shitty_browser'));
}
}
// this is horrible
switch($acceptance->checkoutable_type){
// this is now slightly less horrible
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
switch ($acceptance->checkoutable_type) {
case 'App\Models\Asset':
$pdf_view_route ='account.accept.accept-asset-eula';
$asset_model = AssetModel::find($item->model_id);
$display_model = $asset_model->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Accessory':
$pdf_view_route ='account.accept.accept-accessory-eula';
$accessory = Accessory::find($item->id);
$display_model = $accessory->name;
$assigned_to = User::find($item->assignedTo);
break;
case 'App\Models\LicenseSeat':
$pdf_view_route ='account.accept.accept-license-eula';
$license = License::find($item->license_id);
$display_model = $license->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Component':
$pdf_view_route ='account.accept.accept-component-eula';
$component = Component::find($item->id);
$display_model = $component->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
case 'App\Models\Consumable':
$pdf_view_route ='account.accept.accept-consumable-eula';
$consumable = Consumable::find($item->id);
$display_model = $consumable->name;
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
break;
}
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
// $pdf_view_route ='account.accept.accept-asset-eula';
// $asset_model = AssetModel::find($item->model_id);
// $display_model = $asset_model->name;
// $assigned_to = User::find($item->assigned_to)->present()->fullName;
//
// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
// $pdf_view_route ='account.accept.accept-accessory-eula';
// $accessory = Accessory::find($item->id);
// $display_model = $accessory->name;
// $assigned_to = User::find($item->assignedTo);
//
// }
/**
* Gather the data for the PDF. We fire this whether there is a signature required or not,
@@ -222,8 +204,8 @@ class AcceptanceController extends Controller
'item_model' => $display_model,
'item_serial' => $item->serial,
'eula' => $item->getEula(),
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
@@ -233,7 +215,7 @@ class AcceptanceController extends Controller
if ($pdf_view_route!='') {
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
$pdf = Pdf::loadView($pdf_view_route, $data);
$pdf = Pdf::loadView('account.accept.accept-item', $data);
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
}
@@ -273,7 +255,7 @@ class AcceptanceController extends Controller
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
'declined_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'date_settings' => $branding_settings->date_display_format,
@@ -26,10 +26,7 @@ class AccessoriesController extends Controller
*/
public function index(Request $request)
{
if ($request->user()->cannot('reports.view')) {
$this->authorize('view', Accessory::class);
}
$this->authorize('view', Accessory::class);
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.
@@ -44,13 +41,10 @@ class AccessoriesController extends Controller
'min_amt',
'company_id',
'notes',
'users_count',
'qty',
];
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier')
->withCount('users as users_count');
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier');
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
+21 -47
View File
@@ -100,8 +100,6 @@ class AssetsController extends Controller
'checkout_counter',
'checkin_counter',
'requests_counter',
'byod',
'asset_eol_date',
];
$filter = [];
@@ -129,6 +127,7 @@ class AssetsController extends Controller
// They are also used by the individual searches on detail pages like
// locations, etc.
// Search custom fields by column name
foreach ($all_custom_fields as $field) {
if ($request->filled($field->db_column_name())) {
@@ -136,6 +135,7 @@ class AssetsController extends Controller
}
}
if ($request->filled('status_id')) {
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
@@ -172,10 +172,6 @@ class AssetsController extends Controller
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('asset_eol_date')) {
$assets->where('assets.asset_eol_date', '=', $request->input('asset_eol_date'));
}
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
->where('assets.assigned_type', '=', $request->input('assigned_type'));
@@ -193,10 +189,6 @@ class AssetsController extends Controller
$assets->ByDepreciationId($request->input('depreciation_id'));
}
if ($request->filled('byod')) {
$assets->where('assets.byod', '=', $request->input('byod'));
}
$request->filled('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
@@ -274,11 +266,6 @@ class AssetsController extends Controller
// more sad, horrible workarounds for laravel bugs when doing full text searches
$assets->where('assets.assigned_to', '>', '0');
break;
case 'byod':
// This is kind of redundant, since we already check for byod=1 above, but this keeps the
// sidebar nav links a little less chaotic
$assets->where('assets.byod', '=', '1');
break;
default:
if ((! $request->filled('status_id')) && ($settings->show_archived_in_list != '1')) {
@@ -392,24 +379,14 @@ class AssetsController extends Controller
$assets = $assets->withTrashed();
}
if (($assets = $assets->get()) && ($assets->count()) > 0) {
// If there is exactly one result and the deleted parameter is not passed, we should pull the first (and only)
// asset from the returned collection, since transformAsset() expects an Asset object, NOT a collection
if (($assets->count() == 1) && ($request->input('deleted') != 'true')) {
return (new AssetsTransformer)->transformAsset($assets->first());
// If there is more than one result OR if the endpoint is requesting deleted items (even if there is only one
// match, return the normal collection transformed.
} else {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
}
$assets = $assets->get();
if (($assets) && ($assets->count() > 0)) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
// If there are 0 results, return the "no such asset" response
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
@@ -429,14 +406,14 @@ class AssetsController extends Controller
if ($request->input('deleted', 'false') == 'true') {
$assets = $assets->withTrashed();
}
if (($assets = $assets->get()) && ($assets->count()) > 0) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
$assets = $assets->get();
if (($assets) && ($assets->count() > 0)) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
// If there are 0 results, return the "no such asset" response
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
@@ -463,7 +440,7 @@ class AssetsController extends Controller
{
$this->authorize('view', Asset::class);
$this->authorize('view', License::class);
$asset = Asset::where('id', $id)->withTrashed()->firstorfail();
$asset = Asset::where('id', $id)->withTrashed()->first();
$licenses = $asset->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
@@ -832,6 +809,7 @@ class AssetsController extends Controller
} elseif (request('checkout_to_type') == 'asset') {
$target = Asset::where('id', '!=', $asset_id)->find(request('assigned_asset'));
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
$error_payload['target_id'] = $request->input('assigned_asset');
@@ -859,8 +837,7 @@ class AssetsController extends Controller
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
$expected_checkin = request('expected_checkin', null);
$note = request('note', null);
// Using `->has` preserves the asset name if the name parameter was not included in request.
$asset_name = request()->has('name') ? request('name') : $asset->name;
$asset_name = request('name', null);
// Set the location ID to the RTD location id if there is one
// Wait, why are we doing this? This overrides the stuff we set further up, which makes no sense.
@@ -940,21 +917,18 @@ class AssetsController extends Controller
* @since [v6.0]
* @return JsonResponse
*/
public function checkinByTag(Request $request, $tag = null)
public function checkinByTag(Request $request)
{
$this->authorize('checkin', Asset::class);
if(null == $tag && null !== ($request->input('asset_tag'))) {
$tag = $request->input('asset_tag');
}
$asset = Asset::where('asset_tag', $tag)->first();
$asset = Asset::where('asset_tag', $request->input('asset_tag'))->first();
if ($asset) {
return $this->checkin($request, $asset->id);
}
return response()->json(Helper::formatStandardApiResponse('error', [
'asset'=> e($tag)
], 'Asset with tag '.e($tag).' not found'));
'asset'=> e($request->input('asset_tag'))
], 'Asset with tag '.e($request->input('asset_tag')).' not found'));
}
@@ -10,7 +10,6 @@ use App\Models\Category;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class CategoriesController extends Controller
{
@@ -24,50 +23,10 @@ class CategoriesController extends Controller
public function index(Request $request)
{
$this->authorize('view', Category::class);
$allowed_columns = [
'id',
'name',
'category_type',
'category_type',
'use_default_eula',
'eula_text',
'require_acceptance',
'checkin_email',
'assets_count',
'accessories_count',
'consumables_count',
'components_count',
'licenses_count',
'image',
];
$categories = Category::select([
'id',
'created_at',
'updated_at',
'name', 'category_type',
'use_default_eula',
'eula_text',
'require_acceptance',
'checkin_email',
'image'
])->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
/*
* This checks to see if we should override the Admin Setting to show archived assets in list.
* We don't currently use it within the Snipe-IT GUI, but will be useful for API integrations where they
* may actually need to fetch assets that are archived.
*
* @see \App\Models\Category::showableAssets()
*/
if ($request->input('archived')=='true') {
$categories = $categories->withCount('assets as assets_count');
} else {
$categories = $categories->withCount('showableAssets as assets_count');
}
$allowed_columns = ['id', 'name', 'category_type', 'category_type', 'use_default_eula', 'eula_text', 'require_acceptance', 'checkin_email', 'assets_count', 'accessories_count', 'consumables_count', 'components_count', 'licenses_count', 'image'];
$categories = Category::select(['id', 'created_at', 'updated_at', 'name', 'category_type', 'use_default_eula', 'eula_text', 'require_acceptance', 'checkin_email', 'image'])
->withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count');
if ($request->filled('search')) {
$categories = $categories->TextSearch($request->input('search'));
@@ -148,7 +107,7 @@ class CategoriesController extends Controller
public function show($id)
{
$this->authorize('view', Category::class);
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
$category = Category::findOrFail($id);
return (new CategoriesTransformer)->transformCategory($category);
}
@@ -167,14 +126,8 @@ class CategoriesController extends Controller
{
$this->authorize('update', Category::class);
$category = Category::findOrFail($id);
// Don't allow the user to change the category_type once it's been created
if (($request->filled('category_type')) && ($category->category_type != $request->input('category_type'))) {
return response()->json(
Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.update.cannot_change_category_type'))
);
}
$category->fill($request->all());
$category->category_type = strtolower($request->input('category_type'));
$category = $request->handleImages($category);
if ($category->save()) {
@@ -195,7 +148,7 @@ class CategoriesController extends Controller
public function destroy($id)
{
$this->authorize('delete', Category::class);
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
$category = Category::findOrFail($id);
if (! $category->isDeletable()) {
return response()->json(
@@ -12,7 +12,6 @@ use App\Http\Requests\ImageUploadRequest;
use App\Events\CheckoutableCheckedIn;
use App\Events\ComponentCheckedIn;
use App\Models\Asset;
use Illuminate\Support\Facades\Validator;
class ComponentsController extends Controller
{
@@ -226,30 +225,20 @@ class ComponentsController extends Controller
public function checkout(Request $request, $componentId)
{
// Check if the component exists
if (!$component = Component::find($componentId)) {
if (is_null($component = Component::find($componentId))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.does_not_exist')));
}
$this->authorize('checkout', $component);
$validator = Validator::make($request->all(), [
'asset_id' => 'required|exists:assets,id',
'assigned_qty' => "required|numeric|min:1|digits_between:1,".$component->numRemaining(),
]);
if ($validator->fails()) {
return response()->json(Helper::formatStandardApiResponse('error', $validator->errors()));
}
// Make sure there is at least one available to checkout
if ($component->numRemaining() <= $request->get('assigned_qty')) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->get('assigned_qty')])));
}
if ($component->numRemaining() >= $request->get('assigned_qty')) {
$asset = Asset::find($request->input('assigned_to'));
if (!$asset = Asset::find($request->input('assigned_to'))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')));
}
// Update the accessory data
$component->assigned_to = $request->input('assigned_to');
$component->assets()->attach($component->id, [
@@ -266,7 +255,7 @@ class ComponentsController extends Controller
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.checkout.unavailable', ['remaining' => $component->numRemaining(), 'requested' => $request->get('assigned_qty')])));
return response()->json(Helper::formatStandardApiResponse('error', null, 'Not enough components remaining: '.$component->numRemaining().' remaining, '.$request->get('assigned_qty').' requested.'));
}
/**
@@ -154,7 +154,7 @@ class ConsumablesController extends Controller
public function show($id)
{
$this->authorize('view', Consumable::class);
$consumable = Consumable::with('users')->findOrFail($id);
$consumable = Consumable::findOrFail($id);
return (new ConsumablesTransformer)->transformConsumable($consumable);
}
@@ -253,39 +253,33 @@ class ConsumablesController extends Controller
public function checkout(Request $request, $id)
{
// Check if the consumable exists
if (!$consumable = Consumable::with('users')->find($id)) {
if (is_null($consumable = Consumable::find($id))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.does_not_exist')));
}
$this->authorize('checkout', $consumable);
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.checkout.unavailable')));
\Log::debug('No enough remaining');
}
if ($consumable->qty > 0) {
// Check if the user exists - @TODO: this should probably be handled via validation, not here??
if (!$user = User::find($request->input('assigned_to'))) {
// Return error message
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
\Log::debug('No valid user');
}
// Check if the user exists
$assigned_to = $request->input('assigned_to');
if (is_null($user = User::find($assigned_to))) {
// Return error message
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
}
// Update the consumable data
$consumable->assigned_to = $request->input('assigned_to');
// Update the consumable data
$consumable->assigned_to = e($assigned_to);
$consumable->users()->attach($consumable->id,
[
'consumable_id' => $consumable->id,
'user_id' => $user->id,
'assigned_to' => $request->input('assigned_to'),
'note' => $request->input('note'),
]
);
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'user_id' => $user->id,
'assigned_to' => $assigned_to,
'note' => $request->input('note'),
]);
// Log checkout event
$logaction = $consumable->logCheckout($request->input('note'), $user);
$logaction = $consumable->logCheckout(e($request->input('note')), $user);
$data['log_id'] = $logaction->id;
$data['eula'] = $consumable->getEula();
$data['first_name'] = $user->first_name;
@@ -295,7 +289,9 @@ class ConsumablesController extends Controller
$data['require_acceptance'] = $consumable->requireAcceptance();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
}
return response()->json(Helper::formatStandardApiResponse('error', null, 'No consumables remaining'));
}
/**
@@ -33,7 +33,7 @@ class CustomFieldsetsController extends Controller
*/
public function index()
{
$this->authorize('index', CustomField::class);
$this->authorize('index', CustomFieldset::class);
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
@@ -49,7 +49,7 @@ class CustomFieldsetsController extends Controller
*/
public function show($id)
{
$this->authorize('view', CustomField::class);
$this->authorize('view', CustomFieldset::class);
if ($fieldset = CustomFieldset::find($id)) {
return (new CustomFieldsetsTransformer)->transformCustomFieldset($fieldset);
}
@@ -68,7 +68,7 @@ class CustomFieldsetsController extends Controller
*/
public function update(Request $request, $id)
{
$this->authorize('update', CustomField::class);
$this->authorize('update', CustomFieldset::class);
$fieldset = CustomFieldset::findOrFail($id);
$fieldset->fill($request->all());
@@ -89,7 +89,7 @@ class CustomFieldsetsController extends Controller
*/
public function store(Request $request)
{
$this->authorize('create', CustomField::class);
$this->authorize('create', CustomFieldset::class);
$fieldset = new CustomFieldset;
$fieldset->fill($request->all());
@@ -109,7 +109,7 @@ class CustomFieldsetsController extends Controller
*/
public function destroy($id)
{
$this->authorize('delete', CustomField::class);
$this->authorize('delete', CustomFieldset::class);
$fieldset = CustomFieldset::findOrFail($id);
$modelsCount = $fieldset->models->count();
@@ -136,7 +136,7 @@ class CustomFieldsetsController extends Controller
*/
public function fields($id)
{
$this->authorize('view', CustomField::class);
$this->authorize('view', CustomFieldset::class);
$set = CustomFieldset::findOrFail($id);
$fields = $set->fields;
@@ -153,7 +153,7 @@ class CustomFieldsetsController extends Controller
*/
public function fieldsWithDefaultValues($fieldsetId, $modelId)
{
$this->authorize('view', CustomField::class);
$this->authorize('view', CustomFieldset::class);
$set = CustomFieldset::findOrFail($fieldsetId);
+7 -13
View File
@@ -8,7 +8,6 @@ use App\Http\Transformers\GroupsTransformer;
use App\Models\Group;
use Illuminate\Http\Request;
class GroupsController extends Controller
{
/**
@@ -20,8 +19,6 @@ class GroupsController extends Controller
*/
public function index(Request $request)
{
$this->authorize('superadmin');
$this->authorize('view', Group::class);
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
@@ -62,11 +59,9 @@ class GroupsController extends Controller
*/
public function store(Request $request)
{
$this->authorize('superadmin');
$this->authorize('create', Group::class);
$group = new Group;
$group->name = $request->input('name');
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
$group->fill($request->all());
if ($group->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.create.success')));
@@ -85,7 +80,7 @@ class GroupsController extends Controller
*/
public function show($id)
{
$this->authorize('superadmin');
$this->authorize('view', Group::class);
$group = Group::findOrFail($id);
return (new GroupsTransformer)->transformGroup($group);
@@ -102,11 +97,9 @@ class GroupsController extends Controller
*/
public function update(Request $request, $id)
{
$this->authorize('superadmin');
$this->authorize('update', Group::class);
$group = Group::findOrFail($id);
$group->name = $request->input('name');
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
$group->fill($request->all());
if ($group->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.update.success')));
@@ -125,8 +118,9 @@ class GroupsController extends Controller
*/
public function destroy($id)
{
$this->authorize('superadmin');
$this->authorize('delete', Group::class);
$group = Group::findOrFail($id);
$this->authorize('delete', $group);
$group->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/groups/message.delete.success')));
+10 -41
View File
@@ -10,7 +10,6 @@ use App\Models\Asset;
use App\Models\Company;
use App\Models\Import;
use Artisan;
use Illuminate\Database\Eloquent\JsonEncodingException;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
@@ -36,7 +35,7 @@ class ImportController extends Controller
* Process and store a CSV upload file.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @return \Illuminate\Http\Response
*/
public function store()
{
@@ -57,7 +56,7 @@ class ImportController extends Controller
'text/tsv', ])) {
$results['error'] = 'File type must be CSV. Uploaded file is '.$file->getMimeType();
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 422);
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
}
//TODO: is there a lighter way to do this?
@@ -65,19 +64,7 @@ class ImportController extends Controller
ini_set('auto_detect_line_endings', '1');
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
try {
$import->header_row = $reader->fetchOne(0);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.header_row_has_malformed_characters')
),
422
);
}
$import->header_row = $reader->fetchOne(0);
//duplicate headers check
$duplicate_headers = [];
@@ -95,22 +82,11 @@ class ImportController extends Controller
}
}
if (count($duplicate_headers) > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)),422);
return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)), 500); //should this be '4xx'?
}
try {
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.content_row_has_malformed_characters')
),
422
);
}
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
$date = date('Y-m-d-his');
$fixed_filename = str_slug($file->getClientOriginalName());
@@ -126,25 +102,18 @@ class ImportController extends Controller
}
$file_name = date('Y-m-d-his').'-'.$fixed_filename;
$import->file_path = $file_name;
$import->filesize = null;
if (!file_exists($path.'/'.$file_name)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 500);
}
$import->filesize = filesize($path.'/'.$file_name);
$import->save();
$results[] = $import;
}
$results = (new ImportsTransformer)->transformImports($results);
return response()->json([
return [
'files' => $results,
]);
];
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 422);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 500);
}
/**
@@ -158,7 +127,7 @@ class ImportController extends Controller
$this->authorize('import');
// Run a backup immediately before processing
if ($request->get('run-backup')) {
if ($request->has('run-backup')) {
\Log::debug('Backup manually requested via importer');
Artisan::call('backup:run');
} else {
@@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Laravel\Passport\TokenRepository;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Support\Facades\Gate;
use Gate;
use DB;
class ProfileController extends Controller
@@ -57,12 +57,8 @@ class ReportsController extends Controller
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
$offset = request('offset', 0);
$limit = request('limit', 50);
$total = $actionlogs->count();
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
return response()->json((new ActionlogsTransformer)->transformActionlogs($actionlogs, $total), 200, ['Content-Type' => 'application/json;charset=utf8'], JSON_UNESCAPED_UNICODE);
@@ -143,6 +143,47 @@ class SettingsController extends Controller
}
public function slacktest(SlackSettingsRequest $request)
{
$validator = Validator::make($request->all(), [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
]);
if ($validator->fails()) {
return response()->json(['message' => 'Validation failed', 'errors' => $validator->errors()], 422);
}
// If validation passes, continue to the curl request
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($request->input('slack_endpoint'), ['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'Please check the channel name and webhook endpoint URL ('.e($request->input('slack_endpoint')).'). Slack responded with: '.$e->getMessage()], 400);
}
//}
return response()->json(['message' => 'Something went wrong :( '], 400);
}
/**
* Test the email configuration
*
@@ -271,7 +312,7 @@ class SettingsController extends Controller
$headers = ['ContentType' => 'application/zip'];
return Storage::download($path.'/'.$file, $file, $headers);
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found'));
}
}
@@ -196,7 +196,6 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::withCount('assets')->get();
$total = Array();
foreach ($statuslabels as $statuslabel) {
+12 -71
View File
@@ -20,7 +20,6 @@ use Auth;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class UsersController extends Controller
{
@@ -70,7 +69,6 @@ class UsersController extends Controller
'users.ldap_import',
'users.start_date',
'users.end_date',
'users.vip',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
@@ -151,18 +149,6 @@ class UsersController extends Controller
$users = $users->where('remote', '=', $request->input('remote'));
}
if ($request->filled('vip')) {
$users = $users->where('vip', '=', $request->input('vip'));
}
if ($request->filled('two_factor_enrolled')) {
$users = $users->where('two_factor_enrolled', '=', $request->input('two_factor_enrolled'));
}
if ($request->filled('two_factor_optin')) {
$users = $users->where('two_factor_optin', '=', $request->input('two_factor_optin'));
}
if ($request->filled('start_date')) {
$users = $users->where('users.start_date', '=', $request->input('start_date'));
}
@@ -171,6 +157,7 @@ class UsersController extends Controller
$users = $users->where('users.end_date', '=', $request->input('end_date'));
}
if ($request->filled('assets_count')) {
$users->has('assets', '=', $request->input('assets_count'));
}
@@ -192,6 +179,7 @@ class UsersController extends Controller
}
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$offset = (($users) && (request('offset') > $users->count())) ? 0 : request('offset', 0);
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
// case we override with the actual count, so we should return 0 items.
@@ -217,51 +205,14 @@ class UsersController extends Controller
case 'company':
$users = $users->OrderCompany($order);
break;
case 'first_name':
$users->orderBy('first_name', $order);
$users->orderBy('last_name', $order);
break;
case 'last_name':
$users->orderBy('last_name', $order);
$users->orderBy('first_name', $order);
break;
default:
$allowed_columns =
[
'last_name',
'first_name',
'email',
'jobtitle',
'username',
'employee_num',
'assets',
'accessories',
'consumables',
'licenses',
'groups',
'activated',
'created_at',
'two_factor_enrolled',
'two_factor_optin',
'last_login',
'assets_count',
'licenses_count',
'consumables_count',
'accessories_count',
'phone',
'address',
'city',
'state',
'country',
'zip',
'id',
'ldap_import',
'two_factor_optin',
'two_factor_enrolled',
'remote',
'vip',
'start_date',
'end_date',
'last_name', 'first_name', 'email', 'jobtitle', 'username', 'employee_num',
'assets', 'accessories', 'consumables', 'licenses', 'groups', 'activated', 'created_at',
'two_factor_enrolled', 'two_factor_optin', 'last_login', 'assets_count', 'licenses_count',
'consumables_count', 'accessories_count', 'phone', 'address', 'city', 'state',
'country', 'zip', 'id', 'ldap_import', 'remote', 'start_date', 'end_date',
];
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
@@ -300,11 +251,9 @@ class UsersController extends Controller
$users = Company::scopeCompanyables($users);
if ($request->filled('search')) {
$users = $users->where(function ($query) use ($request) {
$query->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
});
$users = $users->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
}
$users = $users->orderBy('last_name', 'asc')->orderBy('first_name', 'asc');
@@ -465,13 +414,6 @@ class UsersController extends Controller
// Check if the request has groups passed and has a value
if ($request->filled('groups')) {
$validator = Validator::make($request->all(), [
'groups.*' => 'integer|exists:permission_groups,id',
]);
if ($validator->fails()){
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
}
$user->groups()->sync($request->input('groups'));
// The groups field has been passed but it is null, so we should blank it out
} elseif ($request->has('groups')) {
@@ -565,10 +507,9 @@ class UsersController extends Controller
if (empty($user->email)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
}
$user->notify((new CurrentInventory($user)));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
return response()->Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success'));
}
/**
@@ -82,8 +82,8 @@ class AssetModelsController extends Controller
$model->user_id = Auth::id();
$model->requestable = Request::has('requestable');
if ($request->input('fieldset_id') != '') {
$model->fieldset_id = e($request->input('fieldset_id'));
if ($request->input('custom_fieldset') != '') {
$model->fieldset_id = e($request->input('custom_fieldset'));
}
$model = $request->handleImages($model);
@@ -160,10 +160,10 @@ class AssetModelsController extends Controller
$this->removeCustomFieldsDefaultValues($model);
if ($request->input('fieldset_id') == '') {
if ($request->input('custom_fieldset') == '') {
$model->fieldset_id = null;
} else {
$model->fieldset_id = $request->input('fieldset_id');
$model->fieldset_id = $request->input('custom_fieldset');
if ($this->shouldAddDefaultValues($request->input())) {
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
@@ -444,7 +444,7 @@ class AssetModelsController extends Controller
{
return ! empty($input['add_default_values'])
&& ! empty($input['default_values'])
&& ! empty($input['fieldset_id']);
&& ! empty($input['custom_fieldset']);
}
/**
@@ -10,6 +10,7 @@ use App\Http\Requests\AssetCheckoutRequest;
use App\Models\Asset;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
class AssetCheckoutController extends Controller
{
@@ -24,20 +25,39 @@ class AssetCheckoutController extends Controller
* @since [v1.0]
* @return View
*/
public function create($assetId)
public function create(Request $request, $assetId)
{
// Check if the asset exists
if (is_null($asset = Asset::with('company')->find(e($assetId)))) {
if (is_null($asset = Asset::find(e($assetId)))) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('checkout', $asset);
if ($asset->availableForCheckout()) {
/**
* Set a session variable here for the possible return url - this may or may not be used
* in the store() method below, but we need to set it here, so we know what "back" means.
* We set this here so that we don't end up with UX weirdness if our referrer isn't what we're
* expecting (for example a checkout that happens from a place we didn't plan for yet.
* - @snipe - 2022-12-22
*/
$request->session()->forget('backto_item_type');
$request->session()->forget('backto_item_id');
\Log::debug('dropping session data for backto_item_type and backto_item_id');
// Hard-coding this for now, since we're only workiing with assets, not other first-class items yet
$request->session()->put('backto_item_type', '\App\Models\Asset');
$request->session()->put('backto_item_id', $assetId);
\Log::debug('setting new session data for asset '. $assetId . ' via backto_item_type and backto_item_id');
return view('hardware/checkout', compact('asset'))
->with('statusLabel_list', Helper::deployableStatusLabelList());
}
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
}
@@ -52,26 +72,32 @@ class AssetCheckoutController extends Controller
*/
public function store(AssetCheckoutRequest $request, $assetId)
{
$asset = Asset::find($assetId);
$this->authorize('checkout', $asset);
try {
// Check if the asset exists
if (! $asset = Asset::find($assetId)) {
if (!$asset) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
} elseif (! $asset->availableForCheckout()) {
} elseif (!$asset->availableForCheckout()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkout.not_available'));
}
$this->authorize('checkout', $asset);
$admin = Auth::user();
$target = $this->determineCheckoutTarget($asset);
$asset = $this->updateAssetLocation($asset, $target);
$expected_checkin = '';
$checkout_at = date('Y-m-d H:i:s');
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
$checkout_at = $request->get('checkout_at');
}
$expected_checkin = '';
if ($request->filled('expected_checkin')) {
$expected_checkin = $request->get('expected_checkin');
}
@@ -80,20 +106,32 @@ class AssetCheckoutController extends Controller
$asset->status_id = $request->get('status_id');
}
if(!empty($asset->licenseseats->all())){
if(request('checkout_to_type') == 'user') {
if ($request->filled('next_action')) {
$back_to_route = $request->get('next_action');
}
if(!empty($asset->licenseseats->all())) {
if (request('checkout_to_type') == 'user') {
foreach ($asset->licenseseats as $seat){
$seat->assigned_to = $target->id;
$seat->save();
}
}
}
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $request->get('name'))) {
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
if ($request->get('accept_in_person')=='1') {
return view('hardware/checkout', compact('asset'))
->with('statusLabel_list', Helper::deployableStatusLabelList());
}
return redirect()->route($back_to_route)->with('success', trans('admin/hardware/message.checkout.success'));
}
// Redirect to the asset management page with error
// Redirect to the asset page with error
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors());
} catch (ModelNotFoundException $e) {
return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($asset->getErrors());
@@ -16,7 +16,7 @@ use App\Models\User;
use Auth;
use Carbon\Carbon;
use DB;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
@@ -142,12 +142,10 @@ class AssetsController extends Controller
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
$asset->purchase_date = request('purchase_date', null);
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null);
$asset->requestable = request('requestable', 0);
$asset->rtd_location_id = request('rtd_location_id', null);
$asset->byod = request('byod', 0);
if (! empty($settings->audit_interval)) {
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
@@ -313,8 +311,6 @@ class AssetsController extends Controller
$asset->status_id = $request->input('status_id', null);
$asset->warranty_months = $request->input('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->purchase_date = $request->input('purchase_date', null);
$asset->supplier_id = $request->input('supplier_id', null);
$asset->expected_checkin = $request->input('expected_checkin', null);
@@ -322,7 +318,6 @@ class AssetsController extends Controller
// If the box isn't checked, it's not in the request at all.
$asset->requestable = $request->filled('requestable');
$asset->rtd_location_id = $request->input('rtd_location_id', null);
$asset->byod = $request->input('byod', 0);
if ($asset->assigned_to == '') {
$asset->location_id = $request->input('rtd_location_id', null);
@@ -627,11 +622,7 @@ class AssetsController extends Controller
$csv->setHeaderOffset(0);
$header = $csv->getHeader();
$isCheckinHeaderExplicit = in_array('checkin date', (array_map('strtolower', $header)));
try {
$results = $csv->getRecords();
} catch (\Exception $e) {
return back()->with('error', trans('general.error_in_import_file', ['error' => $e->getMessage()]));
}
$results = $csv->getRecords();
$item = [];
$status = [];
$status['error'] = [];
@@ -49,7 +49,6 @@ class BulkAssetsController extends Controller
->with('settings', Setting::getSettings())
->with('bulkedit', true)
->with('count', 0);
case 'delete':
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
$assets->each(function ($asset) {
@@ -57,15 +56,6 @@ class BulkAssetsController extends Controller
});
return view('hardware/bulk-delete')->with('assets', $assets);
case 'restore':
$assets = Asset::withTrashed()->find($asset_ids);
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
return view('hardware/bulk-restore')->with('assets', $assets);
case 'edit':
return view('hardware/bulk')
->with('assets', $asset_ids)
@@ -112,11 +102,8 @@ class BulkAssetsController extends Controller
|| ($request->filled('company_id'))
|| ($request->filled('status_id'))
|| ($request->filled('model_id'))
|| ($request->filled('next_audit_date'))
|| ($request->filled('null_purchase_date'))
|| ($request->filled('null_expected_checkin_date'))
|| ($request->filled('null_next_audit_date'))
) {
foreach ($assets as $assetId) {
@@ -129,8 +116,7 @@ class BulkAssetsController extends Controller
->conditionallyAddItem('requestable')
->conditionallyAddItem('status_id')
->conditionallyAddItem('supplier_id')
->conditionallyAddItem('warranty_months')
->conditionallyAddItem('next_audit_date');
->conditionallyAddItem('warranty_months');
if ($request->input('null_purchase_date')=='1') {
$this->update_array['purchase_date'] = null;
@@ -140,10 +126,6 @@ class BulkAssetsController extends Controller
$this->update_array['expected_checkin'] = null;
}
if ($request->input('null_next_audit_date')=='1') {
$this->update_array['next_audit_date'] = null;
}
if ($request->filled('purchase_cost')) {
$this->update_array['purchase_cost'] = Helper::ParseCurrency($request->input('purchase_cost'));
}
@@ -306,8 +288,7 @@ class BulkAssetsController extends Controller
foreach ($asset_ids as $asset_id) {
$asset = Asset::findOrFail($asset_id);
$this->authorize('checkout', $asset);
$error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
$error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), null);
if ($target->location_id != '') {
$asset->location_id = $target->location_id;
@@ -330,18 +311,5 @@ class BulkAssetsController extends Controller
} catch (ModelNotFoundException $e) {
return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors());
}
}
public function restore(Request $request) {
$assetIds = $request->get('ids');
if (empty($assetIds)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
} else {
foreach ($assetIds as $key => $assetId) {
$asset = Asset::withTrashed()->find($assetId);
$asset->restore();
}
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
}
}
}
@@ -92,7 +92,7 @@ class BulkAssetModelsController extends Controller
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
return redirect()->route('models.index')
->with('success', trans_choice('admin/models/message.bulkedit.success', count($models_raw_array), ['model_count' => count($models_raw_array)]));
->with('success', trans('admin/models/message.bulkedit.success'));
}
return redirect()->route('models.index')
@@ -33,11 +33,6 @@ class ComponentCheckoutController extends Controller
}
$this->authorize('checkout', $component);
// Make sure there is at least one available to checkout
if ($component->numRemaining() <= 0){
return redirect()->route('components.index')->with('error', trans('admin/components/message.checkout.unavailable'));
}
return view('components/checkout', compact('component'));
}
@@ -55,7 +50,7 @@ class ComponentCheckoutController extends Controller
public function store(Request $request, $componentId)
{
// Check if the component exists
if (!$component = Component::find($componentId)) {
if (is_null($component = Component::find($componentId))) {
// Redirect to the component management page with error
return redirect()->route('components.index')->with('error', trans('admin/components/message.not_found'));
}
@@ -63,15 +58,9 @@ class ComponentCheckoutController extends Controller
$this->authorize('checkout', $component);
$max_to_checkout = $component->numRemaining();
// Make sure there is at least one available to checkout
if ($max_to_checkout <= $request->get('assigned_qty')) {
return redirect()->back()->withInput()->with('error', trans('admin/components/message.checkout.unavailable', ['remaining' => $max_to_checkout, 'requested' => $request->get('assigned_qty')]));
}
$validator = Validator::make($request->all(), [
'asset_id' => 'required|exists:assets,id',
'assigned_qty' => "required|numeric|min:1|digits_between:1,$max_to_checkout",
'asset_id' => 'required',
'assigned_qty' => "required|numeric|between:1,$max_to_checkout",
]);
if ($validator->fails()) {
@@ -80,17 +69,24 @@ class ComponentCheckoutController extends Controller
->withInput();
}
$admin_user = Auth::user();
$asset_id = e($request->input('asset_id'));
// Check if the user exists
$asset = Asset::find($request->input('asset_id'));
if (is_null($asset = Asset::find($asset_id))) {
// Redirect to the component management page with error
return redirect()->route('components.index')->with('error', trans('admin/components/message.asset_does_not_exist'));
}
// Update the component data
$component->asset_id = $request->input('asset_id');
$component->asset_id = $asset_id;
$component->assets()->attach($component->id, [
'component_id' => $component->id,
'user_id' => Auth::user(),
'user_id' => $admin_user->id,
'created_at' => date('Y-m-d H:i:s'),
'assigned_qty' => $request->input('assigned_qty'),
'asset_id' => $request->input('asset_id'),
'asset_id' => $asset_id,
'note' => $request->input('note'),
]);
@@ -24,16 +24,9 @@ class ConsumableCheckoutController extends Controller
*/
public function create($consumableId)
{
if (is_null($consumable = Consumable::with('users')->find($consumableId))) {
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
}
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0){
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
}
$this->authorize('checkout', $consumable);
return view('consumables/checkout', compact('consumable'));
@@ -51,18 +44,12 @@ class ConsumableCheckoutController extends Controller
*/
public function store(Request $request, $consumableId)
{
if (is_null($consumable = Consumable::with('users')->find($consumableId))) {
if (is_null($consumable = Consumable::find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
}
$this->authorize('checkout', $consumable);
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
}
$admin_user = Auth::user();
$assigned_to = e($request->input('assigned_to'));
+2 -2
View File
@@ -9,11 +9,11 @@
*
* **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](https://snipe-it.readme.io) for
* [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](https://snipe-it.readme.io/docs/contributing-overview).
* 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)
@@ -109,9 +109,9 @@ class CustomFieldsController extends Controller
if ($request->filled('custom_format')) {
$field->format = $request->get('custom_format');
$field->format = e($request->get('custom_format'));
} else {
$field->format = $request->get('format');
$field->format = e($request->get('format'));
}
if ($field->save()) {
@@ -75,9 +75,9 @@ class CustomFieldsetsController extends Controller
*/
public function create()
{
$this->authorize('create', CustomField::class);
$this->authorize('create', CustomFieldset::class);
return view('custom_fields.fieldsets.edit')->with('item', new CustomFieldset());
return view('custom_fields.fieldsets.edit');
}
/**
@@ -91,7 +91,7 @@ class CustomFieldsetsController extends Controller
*/
public function store(Request $request)
{
$this->authorize('create', CustomField::class);
$this->authorize('create', CustomFieldset::class);
$cfset = new CustomFieldset([
'name' => e($request->get('name')),
@@ -110,52 +110,31 @@ class CustomFieldsetsController extends Controller
}
/**
* Presents edit form for fieldset
* What the actual fuck, Brady?
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @todo Uhh, build this?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v6.0.14]
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
* @since [v1.8]
* @return Fuckall
*/
public function edit($id)
{
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
return view('custom_fields.fieldsets.edit')->with('item', $fieldset);
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
//
}
/**
* Saves updated fieldset data
* GET IN THE SEA BRADY.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @todo Uhh, build this too?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @param int $id
* @since [v6.0.14]
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
* @since [v1.8]
* @return Fuckall
*/
public function update(Request $request, $id)
public function update($id)
{
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
$fieldset->name = $request->input('name');
if ($fieldset->save()) {
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/general.fieldset_updated'));
}
return redirect()->back()->withInput()->withErrors($fieldset->getErrors());
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
//
}
/**
@@ -223,7 +202,7 @@ class CustomFieldsetsController extends Controller
*/
public function makeFieldRequired($fieldset_id, $field_id)
{
$this->authorize('update', CustomField::class);
$this->authorize('update', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fields[$field->id] = ['required' => 1];
@@ -241,7 +220,7 @@ class CustomFieldsetsController extends Controller
*/
public function makeFieldOptional($fieldset_id, $field_id)
{
$this->authorize('update', CustomField::class);
$this->authorize('update', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fields[$field->id] = ['required' => 0];
+6 -5
View File
@@ -92,7 +92,7 @@ class GroupsController extends Controller
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found'));
}
/**
@@ -107,7 +107,7 @@ class GroupsController extends Controller
public function update(Request $request, $id = null)
{
if (! $group = Group::find($id)) {
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
$group->name = $request->input('name');
$group->permissions = json_encode($request->input('permission'));
@@ -133,13 +133,14 @@ class GroupsController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Exception
*/
public function destroy($id)
public function destroy($id = null)
{
if (! config('app.lock_passwords')) {
if (! $group = Group::find($id)) {
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
$group->delete();
// Redirect to the group management page
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.delete'));
}
@@ -163,6 +164,6 @@ class GroupsController extends Controller
return view('groups/view', compact('group'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers;
use App\Http\Transformers\ImportsTransformer;
use App\Models\Asset;
use App\Models\Import;
class ImportsController extends Controller
{
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function index()
{
$this->authorize('import');
$imports = (new ImportsTransformer)->transformImports(Import::latest()->get());
return view('importer/import')->with('imports', $imports);
}
}
@@ -59,12 +59,6 @@ class LicenseCheckinController extends Controller
}
$license = License::find($licenseSeat->license_id);
// LicenseSeat is not assigned, it can't be checked in
if (is_null($licenseSeat->assigned_to) && is_null($licenseSeat->asset_id)) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkin.error'));
}
$this->authorize('checkout', $license);
if (! $license->reassignable) {
@@ -91,30 +91,29 @@ class LicenseFilesController extends Controller
*/
public function destroy($licenseId = null, $fileId = null)
{
if ($license = License::find($licenseId)) {
$license = License::find($licenseId);
// the asset is valid
if (isset($license->id)) {
$this->authorize('update', $license);
$log = Actionlog::find($fileId);
if ($log = Actionlog::find($fileId)) {
// Remove the file if one exists
if (Storage::exists('licenses/'.$log->filename)) {
try {
Storage::delete('licenses/'.$log->filename);
} catch (\Exception $e) {
\Log::debug($e);
}
// Remove the file if one exists
if (Storage::exists('licenses/'.$log->filename)) {
try {
Storage::delete('licenses/'.$log->filename);
} catch (\Exception $e) {
\Log::debug($e);
}
$log->delete();
return redirect()->back()
->with('success', trans('admin/hardware/message.deletefile.success'));
}
return redirect()->route('licenses.index')->with('error', trans('general.log_does_not_exist'));
$log->delete();
return redirect()->back()
->with('success', trans('admin/hardware/message.deletefile.success'));
}
// Redirect to the licence management page
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));
}
@@ -130,6 +129,7 @@ class LicenseFilesController extends Controller
*/
public function show($licenseId = null, $fileId = null, $download = true)
{
\Log::info('Private filesystem is: '.config('filesystems.default'));
$license = License::find($licenseId);
// the license is valid
@@ -227,36 +227,6 @@ class LocationsController extends Controller
}
/**
* Returns a view that presents a form to clone a location.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v6.0.14]
* @return View
*/
public function getClone($locationId = null)
{
$this->authorize('create', Location::class);
// Check if the asset exists
if (is_null($location_to_clone = Location::find($locationId))) {
// Redirect to the asset management page
return redirect()->route('licenses.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
$location = clone $location_to_clone;
// unset these values
$location->id = null;
$location->image = null;
return view('locations/edit')
->with('item', $location);
}
public function print_all_assigned($id)
{
if ($location = Location::where('id', $id)->first()) {
+1 -1
View File
@@ -17,7 +17,7 @@ class ModalController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net]
* @return View
*/
public function show ($type, $itemId = null) {
function show ($type, $itemId = null) {
// These values should correspond to a file in resources/views/modals/
$allowed_types = [
+31 -3
View File
@@ -8,7 +8,7 @@ use App\Models\Setting;
use App\Models\User;
use App\Notifications\CurrentInventory;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
@@ -67,9 +67,37 @@ class ProfileController extends Controller
$user->location_id = $request->input('location_id');
}
// Handle the avatar upload and/or delete if necessary
app('\App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
if ($request->input('avatar_delete') == 1) {
$user->avatar = null;
}
if ($request->hasFile('avatar')) {
$path = 'avatars';
if (! Storage::disk('public')->exists($path)) {
Storage::disk('public')->makeDirectory($path, 775);
}
$upload = $image = $request->file('avatar');
$ext = $image->getClientOriginalExtension();
$file_name = 'avatar-'.str_random(18).'.'.$ext;
if ($image->getClientOriginalExtension() != 'svg') {
$upload = Image::make($image->getRealPath())->resize(84, 84);
}
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($path.'/'.$file_name, (string) $upload->encode());
// Remove Current image if exists
if (($user->avatar) && (Storage::disk('public')->exists($path.'/'.$user->avatar))) {
Storage::disk('public')->delete($path.'/'.$user->avatar);
}
$user->avatar = $file_name;
}
if ($user->save()) {
return redirect()->route('profile')->with('success', 'Account successfully updated');
+6 -7
View File
@@ -51,8 +51,9 @@ class ReportsController extends Controller
public function getAccessoryReport()
{
$this->authorize('reports.view');
$accessories = Accessory::orderBy('created_at', 'DESC')->with('company')->get();
return view('reports/accessories');
return view('reports/accessories', compact('accessories'));
}
/**
@@ -284,7 +285,7 @@ class ReportsController extends Controller
$row = [
$actionlog->created_at,
($actionlog->admin) ? e($actionlog->admin->getFullNameAttribute()) : '',
($actionlog->user) ? e($actionlog->user->getFullNameAttribute()) : '',
$actionlog->present()->actionType(),
e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
@@ -1024,11 +1025,7 @@ class ReportsController extends Controller
if (is_null($acceptance->created_at)){
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
} else {
$logItem_res = $assetItem->checkouts()->where('created_at', '=', $acceptance->created_at)->get();
if ($logItem_res->isEmpty()){
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
}
$logItem = $logItem_res[0];
$logItem = $assetItem->checkouts()->where('created_at', '=', $acceptance->created_at)->get()[0];
}
if(!$assetItem->assignedTo->locale){
@@ -1123,6 +1120,8 @@ class ReportsController extends Controller
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
$rows[] = implode(',', $row);
} else {
// Log the error maybe?
}
}
+43 -25
View File
@@ -65,27 +65,18 @@ class SettingsController extends Controller
$start_settings['db_error'] = $e->getMessage();
}
if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER)) {
$protocol = $_SERVER["HTTP_X_FORWARDED_PROTO"] . "://";
} elseif (array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS'])) {
$protocol = "https://";
} else {
$protocol = "http://";
}
$protocol = array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS']) ? 'https://' : 'http://';
if (array_key_exists("HTTP_X_FORWARDED_HOST", $_SERVER)) {
$host = $_SERVER["HTTP_X_FORWARDED_HOST"];
} else {
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) {
$host .= ':'.$port;
}
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) {
$host .= ':'.$port;
}
$pageURL = $protocol.$host.$_SERVER['REQUEST_URI'];
$start_settings['url_config'] = config('app.url').'/setup';
$start_settings['url_valid'] = ($start_settings['url_config'] === $pageURL);
$start_settings['url_valid'] = (url('/').'/setup' === $pageURL);
$start_settings['url_config'] = url('/');
$start_settings['real_url'] = $pageURL;
$start_settings['php_version_min'] = true;
@@ -120,17 +111,17 @@ class SettingsController extends Controller
$start_settings['prod'] = true;
}
$start_settings['owner'] = '';
if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
// This *should* be an array, but we've seen this return a bool in some chrooted environments
if (is_array($owner)) {
$start_settings['owner'] = $owner['name'];
}
$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')) {
if (('root' === $start_settings['owner']) || ('0' === $start_settings['owner'])) {
$start_settings['owner_is_admin'] = true;
} else {
$start_settings['owner_is_admin'] = false;
@@ -688,6 +679,33 @@ class SettingsController extends Controller
return view('settings.slack', compact('setting'));
}
/**
* Return a form to allow a super admin to update settings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v1.0]
*
* @return View
*/
public function postSlack(SlackSettingsRequest $request)
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$setting->slack_endpoint = $request->input('slack_endpoint');
$setting->slack_channel = $request->input('slack_channel');
$setting->slack_botname = $request->input('slack_botname');
if ($setting->save()) {
return redirect()->route('settings.index')
->with('success', trans('admin/settings/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($setting->getErrors());
}
/**
* Return a form to allow a super admin to update settings.
*
@@ -789,7 +807,7 @@ class SettingsController extends Controller
*/
public function getPhpInfo()
{
if (config('app.debug') === true) {
if (true === config('app.debug')) {
return view('settings.phpinfo');
}
@@ -2,7 +2,6 @@
namespace App\Http\Controllers\Users;
use App\Events\UserMerged;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
@@ -14,7 +13,6 @@ use App\Models\LicenseSeat;
use App\Models\ConsumableAssignment;
use App\Models\Consumable;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
@@ -23,7 +21,7 @@ use Illuminate\Support\Facades\Password;
class BulkUsersController extends Controller
{
/**
* Returns a view that confirms the user's a bulk action will be applied to.
* Returns a view that confirms the user's a bulk delete will be applied to.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.7]
@@ -37,32 +35,16 @@ class BulkUsersController extends Controller
// Make sure there were users selected
if (($request->filled('ids')) && (count($request->input('ids')) > 0)) {
// Get the list of affected users
$user_raw_array = request('ids');
$users = User::whereIn('id', $user_raw_array)
->with('groups', 'assets', 'licenses', 'accessories')->get();
// bulk edit, display the bulk edit form
if ($request->input('bulk_actions') == 'edit') {
return view('users/bulk-edit', compact('users'))
->with('groups', Group::pluck('name', 'id'));
// bulk delete, display the bulk delete confirmation form
} elseif ($request->input('bulk_actions') == 'delete') {
return view('users/confirm-bulk-delete')->with('users', $users)->with('statuslabel_list', Helper::statusLabelList());
// merge, confirm they have at least 2 users selected and display the merge screen
} elseif ($request->input('bulk_actions') == 'merge') {
if (($request->filled('ids')) && (count($request->input('ids')) > 1)) {
return view('users/confirm-merge')->with('users', $users);
// Not enough users selected, send them back
} else {
return redirect()->back()->with('error', trans('general.not_enough_users_selected', ['count' => 2]));
}
// bulk password reset, just do the thing
} elseif ($request->input('bulk_actions') == 'bulkpasswordreset') {
foreach ($users as $user) {
if (($user->activated == '1') && ($user->email != '')) {
@@ -77,7 +59,7 @@ class BulkUsersController extends Controller
}
}
return redirect()->back()->with('error', trans('general.no_users_selected'));
return redirect()->back()->with('error', 'No users selected');
}
/**
@@ -94,7 +76,7 @@ class BulkUsersController extends Controller
$this->authorize('update', User::class);
if ((! $request->filled('ids')) || $request->input('ids') <= 0) {
return redirect()->back()->with('error', trans('general.no_users_selected'));
return redirect()->back()->with('error', 'No users selected');
}
$user_raw_array = $request->input('ids');
@@ -123,11 +105,6 @@ class BulkUsersController extends Controller
'warning' => trans('admin/users/message.bulk_manager_warn'),
];
}
if ($request->input('null_location_id')=='1') {
$this->update_array['location_id'] = null;
}
if (! $manager_conflict) {
$this->conditionallyAddItem('manager_id');
}
@@ -186,11 +163,11 @@ class BulkUsersController extends Controller
$this->authorize('update', User::class);
if ((! $request->filled('ids')) || (count($request->input('ids')) == 0)) {
return redirect()->back()->with('error', trans('general.no_users_selected'));
return redirect()->back()->with('error', 'No users selected');
}
if (config('app.lock_passwords')) {
return redirect()->route('users.index')->with('error', trans('general.feature_disabled'));
return redirect()->route('users.index')->with('error', 'Bulk delete is not enabled in this installation');
}
$user_raw_array = request('ids');
@@ -272,80 +249,4 @@ class BulkUsersController extends Controller
$logAction->logaction('checkin from');
}
}
/**
* Save bulk-edited users
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function merge(Request $request)
{
$this->authorize('update', User::class);
if (config('app.lock_passwords')) {
return redirect()->route('users.index')->with('error', trans('general.feature_disabled'));
}
$user_ids_to_merge = $request->input('ids_to_merge');
$user_ids_to_merge = array_diff($user_ids_to_merge, array($request->input('merge_into_id')));
if ((!$request->filled('merge_into_id')) || (count($user_ids_to_merge) < 1)) {
return redirect()->back()->with('error', trans('general.no_users_selected'));
}
// Get the users
$merge_into_user = User::find($request->input('merge_into_id'));
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'licenses', 'consumables','accessories')->get();
$admin = User::find(Auth::user()->id);
// Walk users
foreach ($users_to_merge as $user_to_merge) {
foreach ($user_to_merge->assets as $asset) {
\Log::debug('Updating asset: '.$asset->asset_tag . ' to '.$merge_into_user->id);
$asset->assigned_to = $request->input('merge_into_id');
$asset->save();
}
foreach ($user_to_merge->licenses as $license) {
\Log::debug('Updating license pivot: '.$license->id . ' to '.$merge_into_user->id);
$user_to_merge->licenses()->updateExistingPivot($license->id, ['assigned_to' => $merge_into_user->id]);
}
foreach ($user_to_merge->consumables as $consumable) {
\Log::debug('Updating consumable pivot: '.$consumable->id . ' to '.$merge_into_user->id);
$user_to_merge->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $merge_into_user->id]);
}
foreach ($user_to_merge->accessories as $accessory) {
$user_to_merge->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $merge_into_user->id]);
}
foreach ($user_to_merge->userlog as $log) {
$log->target_id = $user_to_merge->id;
$log->save();
}
User::where('manager_id', '=', $user_to_merge->id)->update(['manager_id' => $merge_into_user->id]);
foreach ($user_to_merge->managedLocations as $managedLocation) {
$managedLocation->manager_id = $merge_into_user->id;
$managedLocation->save();
}
$user_to_merge->delete();
//$user_to_merge->save();
event(new UserMerged($user_to_merge, $merge_into_user, $admin));
}
return redirect()->route('users.index')->with('success', trans('general.merge_success', ['count' => $users_to_merge->count(), 'into_username' => $merge_into_user->username]));
}
}
@@ -121,7 +121,6 @@ class UsersController extends Controller
$user->created_by = Auth::user()->id;
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses= $request->input('autoassign_licenses', 1);
// Strip out the superuser permission if the user isn't a superadmin
$permissions_array = $request->input('permission');
@@ -132,7 +131,7 @@ class UsersController extends Controller
$user->permissions = json_encode($permissions_array);
// we have to invoke the
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
app(\App\Http\Requests\ImageUploadRequest::class)->handleImages($user, 600, 'image', 'avatars', 'avatar');
if ($user->save()) {
if ($request->filled('groups')) {
@@ -272,11 +271,9 @@ class UsersController extends Controller
$user->activated = $request->input('activated', 0);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->vip = $request->input('vip', 0);
$user->website = $request->input('website', null);
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 1);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)
@@ -299,7 +296,7 @@ class UsersController extends Controller
$user->permissions = json_encode($permissions_array);
// Handle uploaded avatar
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
app(\App\Http\Requests\ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
//\Log::debug(print_r($user, true));
-322
View File
@@ -1,322 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Models\CustomField;
use Livewire\Component;
use App\Models\Import;
use Storage;
use Log;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Importer extends Component
{
use AuthorizesRequests;
public $files;
public $progress; //upload progress - '-1' means don't show
public $progress_message;
public $progress_bar_class;
public $message; //status/error message?
public $message_type; //success/error?
//originally from ImporterFile
public $import_errors; //
public ?Import $activeFile = null;
public $importTypes;
public $columnOptions;
public $statusType;
public $statusText;
public $update;
public $send_welcome;
public $run_backup;
public $field_map; // we need a separate variable for the field-mapping, because the keys in the normal array are too complicated for Livewire to understand
public $file_id; // TODO: I can't figure out *why* we need this, but it really seems like we do. I can't seem to pull the id from the activeFile for some reason?
protected $rules = [
'files.*.file_path' => 'required|string',
'files.*.created_at' => 'required|string',
'files.*.filesize' => 'required|integer',
'activeFile' => 'Import',
'activeFile.import_type' => 'string',
'activeFile.field_map' => 'array',
'activeFile.header_row' => 'array',
'field_map' => 'array'
];
public function generate_field_map()
{
\Log::debug("header row is: ".print_r($this->activeFile->header_row,true));
\Log::debug("Field map is: ".print_r($this->field_map,true));
$tmp = array_combine($this->activeFile->header_row, $this->field_map);
return json_encode(array_filter($tmp));
}
// all of these 'statics', alas, may have to change to something else to handle translations?
// I'm not sure. Maybe I use them to 'populate' the translations? TBH, I don't know yet.
static $general = [
'category' => 'Category',
'company' => 'Company',
'email' => 'Email',
'item_name' => 'Item Name',
'location' => 'Location',
'maintained' => 'Maintained',
'manufacturer' => 'Manufacturer',
'notes' => 'Notes',
'order_number' => 'Order Number',
'purchase_cost' => 'Purchase Cost',
'purchase_date' => 'Purchase Date',
'quantity' => 'Quantity',
'requestable' => 'Requestable',
'serial' => 'Serial Number',
'supplier' => 'Supplier',
'username' => 'Username',
'department' => 'Department',
];
static $accessories = [
'model_number' => 'Model Number',
];
static $assets = [
'asset_tag' => 'Asset Tag',
'asset_model' => 'Model Name',
'byod' => 'BYOD',
'checkout_class' => 'Checkout Type',
'checkout_location' => 'Checkout Location',
'image' => 'Image Filename',
'model_number' => 'Model Number',
'full_name' => 'Full Name',
'status' => 'Status',
'warranty_months' => 'Warranty Months',
];
static $consumables = [
'item_no' => "Item Number",
'model_number' => "Model Number",
'min_amt' => "Minimum Quantity",
];
static $licenses = [
'asset_tag' => 'Assigned To Asset',
'expiration_date' => 'Expiration Date',
'full_name' => 'Full Name',
'license_email' => 'Licensed To Email',
'license_name' => 'Licensed To Name',
'purchase_order' => 'Purchase Order',
'reassignable' => 'Reassignable',
'seats' => 'Seats',
];
static $users = [
'employee_num' => 'Employee Number',
'first_name' => 'First Name',
'jobtitle' => 'Job Title',
'last_name' => 'Last Name',
'phone_number' => 'Phone Number',
'manager_first_name' => 'Manager First Name',
'manager_last_name' => 'Manager Last Name',
'activated' => 'Activated',
'address' => 'Address',
'city' => 'City',
'state' => 'State',
'country' => 'Country',
'vip' => 'VIP'
];
//array of "real fieldnames" to a list of aliases for that field
static $aliases = [
'model_number' =>
[
'model',
'model no',
'model no.',
'model number',
'model num',
'model num.'
],
'warranty_months' =>
[
'Warranty',
'Warranty Months'
],
'qty' =>
[
'QTY',
'Quantity'
],
'min_amt' =>
[
'Min Amount',
'Min QTY'
],
'next_audit_date' =>
[
'Next Audit',
],
];
private function getColumns($type)
{
switch ($type) {
case 'asset':
$results = self::$general + self::$assets;
break;
case 'accessory':
$results = self::$general + self::$accessories;
break;
case 'consumable':
$results = self::$general + self::$consumables;
break;
case 'license':
$results = self::$general + self::$licenses;
break;
case 'user':
$results = self::$general + self::$users;
break;
default:
$results = self::$general;
}
asort($results, SORT_FLAG_CASE | SORT_STRING);
if ($type == "asset") {
// add Custom Fields after a horizontal line
$results['-'] = "———" . trans('admin/custom_fields/general.custom_fields') . "———’";
foreach (CustomField::orderBy('name')->get() as $field) {
$results[$field->db_column_name()] = $field->name;
}
}
return $results;
}
public function updating($name, $new_import_type)
{
if ($name == "activeFile.import_type") {
\Log::debug("WE ARE CHANGING THE import_type!!!!! TO: " . $new_import_type);
\Log::debug("so, what's \$this->>field_map at?: " . print_r($this->field_map, true));
// go through each header, find a matching field to try and map it to.
foreach ($this->activeFile->header_row as $i => $header) {
// do we have something mapped already?
if (array_key_exists($i, $this->field_map)) {
// yes, we do. Is it valid for this type of import?
// (e.g. the import type might have been changed...?)
if (array_key_exists($this->field_map[$i], $this->columnOptions[$new_import_type])) {
//yes, this key *is* valid. Continue on to the next field.
continue;
} else {
//no, this key is *INVALID* for this import type. Better set it to null
// and we'll hope that the aliases or something else picks it up.
$this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh.
} // TODO - strictly speaking, this isn't necessary here I don't think.
}
// first, check for exact matches
foreach ($this->columnOptions[$new_import_type] as $value => $text) {
if (strcasecmp($text, $header) === 0) { // case-INSENSITIVe on purpose!
$this->field_map[$i] = $value;
continue 2; //don't bother with the alias check, go to the next header
}
}
// if you got here, we didn't find a match. Try the aliases
foreach (self::$aliases as $key => $alias_values) {
foreach ($alias_values as $alias_value) {
if (strcasecmp($alias_value, $header) === 0) { // aLsO CaSe-INSENSitiVE!
// Make *absolutely* sure that this key actually _exists_ in this import type -
// you can trigger this by importing accessories with a 'Warranty' column (which don't exist
// in "Accessories"!)
if (array_key_exists($key, $this->columnOptions[$new_import_type])) {
$this->field_map[$i] = $key;
continue 3; // bust out of both of these loops; as well as the surrounding one - e.g. move on to the next header
}
}
}
}
// and if you got here, we got nothing. Let's recommend 'null'
$this->field_map[$i] = null; // Booooo :(
}
}
}
public function boot() { // FIXME - delete or undelete.
///////$this->activeFile = null; // I do *not* understand why I have to do this, but, well, whatever.
}
public function mount()
{
$this->authorize('import');
$this->progress = -1; // '-1' means 'don't show the progressbar'
$this->progress_bar_class = 'progress-bar-warning';
\Log::debug("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk
$this->importTypes = [
'asset' => trans('general.assets'),
'accessory' => trans('general.accessories'),
'consumable' => trans('general.consumables'),
'component' => trans('general.components'),
'license' => trans('general.licenses'),
'user' => trans('general.users'),
];
$this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean
foreach($this->importTypes AS $type => $name) {
$this->columnOptions[$type] = $this->getColumns($type);
}
if ($this->activeFile) {
$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : [];
}
}
public function selectFile($id)
{
\Log::debug("TOGGLE EVENT FIRED!");
\Log::debug("The ID we are trying to find is AS FOLLOWS: ".$id);
$this->activeFile = Import::find($id);
$this->field_map = null;
foreach($this->activeFile->header_row as $element) {
if(isset($this->activeFile->field_map[$element])) {
$this->field_map[] = $this->activeFile->field_map[$element];
} else {
$this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings
}
}
//$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; // this is wrong
$this->file_id = $id;
$this->import_errors = null;
$this->statusText = null;
\Log::debug("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type);
}
public function destroy($id)
{
// TODO: why don't we just do File::find($id)? This seems dumb.
foreach($this->files as $file) {
\Log::debug("File id is: ".$file->id);
if($id == $file->id) {
if(Storage::delete('private_uploads/imports/'.$file->file_path)) {
$file->delete();
$this->message = trans('admin/hardware/message.import.file_delete_success');
$this->message_type = 'success';
return;
} else {
$this->message = trans('admin/hardware/message.import.file_delete_error');
$this->message_type = 'danger';
}
}
}
}
public function render()
{
$this->files = Import::orderBy('id','desc')->get(); //HACK - slows down renders.
return view('livewire.importer')
->extends('layouts.default')
->section('content');
}
}
-177
View File
@@ -1,177 +0,0 @@
<?php
namespace App\Http\Livewire;
use GuzzleHttp\Client;
use Livewire\Component;
use App\Models\Setting;
use App\Helpers\Helper;
class SlackSettingsForm extends Component
{
public $webhook_endpoint;
public $webhook_channel;
public $webhook_botname;
public $isDisabled ='' ;
public $webhook_name;
public $webhook_link;
public $webhook_placeholder;
public $webhook_icon;
public $webhook_selected;
public array $webhook_text;
public Setting $setting;
protected $rules = [
'webhook_endpoint' => 'url|required_with:webhook_channel|starts_with:https://hooks.slack.com/services|nullable',
'webhook_channel' => 'required_with:webhook_endpoint|starts_with:#|nullable',
'webhook_botname' => 'string|nullable',
];
public function mount() {
$this->webhook_text= [
"slack" => array(
"name" => trans('admin/settings/general.slack') ,
"icon" => 'fab fa-slack',
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
"link" => 'https://api.slack.com/messaging/webhooks',
),
"general"=> array(
"name" => trans('admin/settings/general.general_webhook'),
"icon" => "fab fa-hashtag",
"placeholder" => "",
"link" => "",
),
];
$this->setting = Setting::getSettings();
$this->save_button = trans('general.save');
$this->webhook_selected = $this->setting->webhook_selected;
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"];
$this->webhook_name = $this->webhook_text[$this->setting->webhook_selected]["name"];
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"];
$this->webhook_endpoint = $this->setting->webhook_endpoint;
$this->webhook_channel = $this->setting->webhook_channel;
$this->webhook_botname = $this->setting->webhook_botname;
$this->webhook_options = $this->setting->webhook_selected;
if($this->setting->webhook_selected == 'general'){
$this->isDisabled='';
}
if($this->setting->webhook_endpoint != null && $this->setting->webhook_channel != null){
$this->isDisabled= '';
}
}
public function updated($field) {
if($this->webhook_selected != 'general') {
$this->validateOnly($field, $this->rules);
}
}
public function updatedWebhookSelected() {
$this->webhook_name = $this->webhook_text[$this->webhook_selected]['name'];
$this->webhook_icon = $this->webhook_text[$this->webhook_selected]["icon"]; ;
$this->webhook_placeholder = $this->webhook_text[$this->webhook_selected]["placeholder"];
$this->webhook_link = $this->webhook_text[$this->webhook_selected]["link"];
if($this->webhook_selected != 'slack'){
$this->isDisabled= '';
$this->save_button = trans('general.save');
}
}
private function isButtonDisabled() {
if($this->webhook_selected == 'slack') {
if (empty($this->webhook_endpoint)) {
$this->isDisabled = 'disabled';
$this->save_button = trans('admin/settings/general.webhook_presave');
}
if (empty($this->webhook_channel)) {
$this->isDisabled = 'disabled';
$this->save_button = trans('admin/settings/general.webhook_presave');
}
}
}
public function render()
{
$this->isButtonDisabled();
return view('livewire.slack-settings-form');
}
public function testWebhook(){
$webhook = new Client([
'base_url' => e($this->webhook_endpoint),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($this->webhook_channel),
'text' => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
'username' => e($this->webhook_botname),
'icon_emoji' => ':heart:',
]);
try {
$webhook->post($this->webhook_endpoint, ['body' => $payload]);
$this->isDisabled='';
$this->save_button = trans('general.save');
return session()->flash('success' , 'Your '.$this->webhook_name.' Integration works!');
} catch (\Exception $e) {
$this->isDisabled= 'disabled';
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
}
return session()->flash('error' , trans('admin/settings/message.webhook.error_misc'));
}
public function clearSettings(){
if (Helper::isDemoMode()) {
session()->flash('error',trans('general.feature_disabled'));
} else {
$this->webhook_endpoint = '';
$this->webhook_channel = '';
$this->webhook_botname = '';
$this->setting->webhook_endpoint = '';
$this->setting->webhook_channel = '';
$this->setting->webhook_botname = '';
$this->setting->save();
session()->flash('success', trans('admin/settings/message.update.success'));
}
}
public function submit()
{
if (Helper::isDemoMode()) {
session()->flash('error',trans('general.feature_disabled'));
} else {
if ($this->webhook_selected != 'general') {
$this->validate($this->rules);
}
$this->setting->webhook_selected = $this->webhook_selected;
$this->setting->webhook_endpoint = $this->webhook_endpoint;
$this->setting->webhook_channel = $this->webhook_channel;
$this->setting->webhook_botname = $this->webhook_botname;
$this->setting->save();
session()->flash('success',trans('admin/settings/message.update.success'));
}
}
}
@@ -52,13 +52,6 @@ class AssetCountForSidebar
\Log::debug($e);
}
try {
$total_byod_sidebar = Asset::where('byod', '=', '1')->count();
view()->share('total_byod_sidebar', $total_byod_sidebar);
} catch (\Exception $e) {
\Log::debug($e);
}
return $next($request);
}
}
+2 -2
View File
@@ -20,13 +20,13 @@ class CheckForSetup
if (Setting::setupCompleted()) {
if ($request->is('setup*')) {
return redirect(config('app.url'));
return redirect(url('/'));
} else {
return $next($request);
}
} else {
if (! ($request->is('setup*')) && ! ($request->is('.env')) && ! ($request->is('health'))) {
return redirect(config('app.url').'/setup');
return redirect(url('/').'/setup');
}
return $next($request);
+1 -1
View File
@@ -11,7 +11,7 @@ class CheckForTwoFactor
/**
* Routes to ignore for Two Factor Auth
*/
public const IGNORE_ROUTES = ['two-factor', 'two-factor-enroll', 'setup', 'logout'];
const IGNORE_ROUTES = ['two-factor', 'two-factor-enroll', 'setup', 'logout'];
/**
* Handle an incoming request.
+1 -1
View File
@@ -3,7 +3,7 @@
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Gate;
use Gate;
class CheckPermissions
{
+1 -1
View File
@@ -24,7 +24,7 @@ class AssetFileRequest extends Request
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
return [
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp|max:'.$max_file_size,
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,webp|max:'.$max_file_size,
];
}
}
+39 -41
View File
@@ -7,9 +7,7 @@ use enshrined\svgSanitize\Sanitizer;
use Intervention\Image\Facades\Image;
use App\Http\Traits\ConvertsBase64ToFiles;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Exception\NotReadableException;
use Storage;
class ImageUploadRequest extends Request
{
@@ -65,13 +63,11 @@ class ImageUploadRequest extends Request
* @param string $path location for uploaded images, defaults to uploads/plural of item type.
* @return SnipeModel Target asset is being checked out to.
*/
public function handleImages($item, $w = 600, $form_fieldname = 'image', $path = null, $db_fieldname = 'image')
public function handleImages($item, $w = 600, $form_fieldname = null, $path = null, $db_fieldname = 'image')
{
$type = strtolower(class_basename(get_class($item)));
if (is_null($path)) {
$path = str_plural($type);
if ($type == 'assetmodel') {
@@ -83,47 +79,49 @@ class ImageUploadRequest extends Request
}
}
if ($this->offsetGet($form_fieldname) instanceof UploadedFile) {
$image = $this->offsetGet($form_fieldname);
\Log::debug('Image is an instance of UploadedFile');
} elseif ($this->hasFile($form_fieldname)) {
$image = $this->file($form_fieldname);
\Log::debug('Just use regular upload for '.$form_fieldname);
if (is_null($form_fieldname)) {
$form_fieldname = 'image';
}
// This is dumb, but we need it for overriding field names for exceptions like avatars and logo uploads
if (is_null($db_fieldname)) {
$use_db_field = $form_fieldname;
} else {
\Log::debug('No image found for form fieldname: '.$form_fieldname);
$use_db_field = $db_fieldname;
}
// ConvertBase64ToFiles just changes object type,
// as it cannot currently insert files to $this->files
if ($this->offsetGet($form_fieldname) instanceof UploadedFile) {
$image=$this->offsetGet($form_fieldname);
} else {
if ($this->hasFile($form_fieldname)) {
$image = $this->file($form_fieldname);
}
}
if (isset($image)) {
\Log::debug($image);
if (!config('app.lock_passwords')) {
$ext = $image->getClientOriginalExtension();
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
$file_name = $type.'-'.$form_fieldname.'-'.str_random(10).'.'.$ext;
\Log::info('File name will be: '.$file_name);
\Log::debug('File extension is: '.$ext);
if (($image->getClientOriginalExtension() !== 'webp') && ($image->getClientOriginalExtension() !== 'svg')) {
\Log::debug('Not an SVG or webp - resize');
\Log::debug('Trying to upload to: '.$path.'/'.$file_name);
try {
$upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
} catch(NotReadableException $e) {
\Log::debug($e);
$validator = \Validator::make([], []);
$validator->errors()->add($form_fieldname, trans('general.unaccepted_image_type', ['mimetype' => $image->getClientMimeType()]));
throw new \Illuminate\Validation\ValidationException($validator);
}
$upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($path.'/'.$file_name, (string) $upload->encode());
} else {
// If the file is a webp, we need to just move it since webp support
// needs to be compiled into gd for resizing to be available
@@ -148,30 +146,30 @@ class ImageUploadRequest extends Request
}
// Remove Current image if exists
if (($item->{$form_fieldname}!='') && (Storage::disk('public')->exists($path.'/'.$item->{$db_fieldname}))) {
if (Storage::disk('public')->exists($path.'/'.$item->{$use_db_field})) {
\Log::debug('A file already exists that we are replacing - we should delete the old one.');
try {
Storage::disk('public')->delete($path.'/'.$item->{$form_fieldname});
Storage::disk('public')->delete($path.'/'.$item->{$use_db_field});
\Log::debug('Old file '.$path.'/'.$file_name.' has been deleted.');
} catch (\Exception $e) {
\Log::debug('Could not delete old file. '.$path.'/'.$file_name.' does not exist?');
}
}
$item->{$db_fieldname} = $file_name;
$item->{$use_db_field} = $file_name;
}
// If the user isn't uploading anything new but wants to delete their old image, do so
} elseif ($this->input('image_delete') == '1') {
\Log::debug('Deleting image');
try {
Storage::disk('public')->delete($path.'/'.$item->{$db_fieldname});
$item->{$db_fieldname} = null;
} catch (\Exception $e) {
\Log::debug($e);
} else {
if ($this->input('image_delete') == '1') {
\Log::debug('Deleting image');
try {
Storage::disk('public')->delete($path.'/'.$item->{$use_db_field});
$item->{$use_db_field} = null;
} catch (\Exception $e) {
\Log::debug($e);
}
}
}
return $item;
+5 -2
View File
@@ -39,12 +39,14 @@ class SaveUserRequest extends FormRequest
// Brand new user
case 'POST':
{
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
if ($this->request->get('ldap_import') == false) {
$rules['password'] = Setting::passwordComplexityRulesSaving('store').'|confirmed';
}
break;
}
// Save all fields
case 'PUT':
@@ -55,11 +57,12 @@ class SaveUserRequest extends FormRequest
// Save only what's passed
case 'PATCH':
{
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
break;
}
default:
break;
default:break;
}
return $rules;
@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
class SlackSettingsRequest 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 [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:"https://hooks.slack.com"|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
'slack_botname' => 'string|nullable',
];
}
}
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Accessory;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -38,8 +38,7 @@ class AccessoriesTransformer
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => (int) $accessory->numRemaining(),
'users_count' => $accessory->users_count,
'remaining_qty' => $accessory->numRemaining(),
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
@@ -51,8 +50,6 @@ class AccessoriesTransformer
'checkin' => false,
'update' => Gate::allows('update', Accessory::class),
'delete' => Gate::allows('delete', Accessory::class),
'clone' => Gate::allows('create', Accessory::class),
];
$permissions_array['user_can_checkout'] = false;
@@ -60,14 +60,12 @@ class ActionlogsTransformer
if ($actionlog->action_type == 'accepted') {
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
} else {
if ($actionlog->item) {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'license') {
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'user') {
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
}
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'license') {
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
} elseif ($actionlog->itemType() == 'user') {
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
}
}
}
@@ -5,7 +5,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Asset;
use App\Models\AssetMaintenance;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class AssetMaintenancesTransformer
@@ -45,10 +45,6 @@ class AssetMaintenancesTransformer
'name'=> e($assetmaintenance->asset->location->name),
] : null,
'rtd_location' => ($assetmaintenance->asset->defaultLoc) ? [
'id' => (int) $assetmaintenance->asset->defaultLoc->id,
'name'=> e($assetmaintenance->asset->defaultLoc->name),
] : null,
'notes' => ($assetmaintenance->notes) ? e($assetmaintenance->notes) : null,
'supplier' => ($assetmaintenance->supplier) ? ['id' => $assetmaintenance->supplier->id, 'name'=> e($assetmaintenance->supplier->name)] : null,
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\AssetModel;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
+3 -6
View File
@@ -5,7 +5,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Asset;
use App\Models\Setting;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
@@ -35,11 +35,8 @@ class AssetsTransformer
'id' => (int) $asset->model->id,
'name'=> e($asset->model->name),
] : null,
'byod' => ($asset->byod ? true : false),
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => ($asset->model->eol != '') ? $asset->model->eol : null,
'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null,
'eol' => ($asset->purchase_date != '') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name),
@@ -84,7 +81,7 @@ class AssetsTransformer
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date, 'date'),
'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'),
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
'age' => $asset->purchase_date ? $asset->purchase_date->diffForHumans() : '',
'age' => $asset->purchase_date ? Helper::AgeFormat($asset->purchase_date) : '',
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Category;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -22,38 +22,18 @@ class CategoriesTransformer
public function transformCategory(Category $category = null)
{
// We only ever use item_count for categories in this transformer, so it makes sense to keep it
// simple and do this switch here.
switch ($category->category_type) {
case 'asset':
$category->item_count = $category->assets_count;
break;
case 'accessory':
$category->item_count = $category->accessories_count;
break;
case 'consumable':
$category->item_count = $category->consumables_count;
break;
case 'component':
$category->item_count = $category->components_count;
break;
default:
$category->item_count = 0;
}
if ($category) {
$array = [
'id' => (int) $category->id,
'name' => e($category->name),
'image' => ($category->image) ? Storage::disk('public')->url('categories/'.e($category->image)) : null,
'category_type' => Helper::categoryTypeList($category->category_type),
'category_type' => ucwords(e($category->category_type)),
'has_eula' => ($category->getEula() ? true : false),
'use_default_eula' => ($category->use_default_eula=='1' ? true : false),
'eula' => ($category->getEula()),
'checkin_email' => ($category->checkin_email == '1'),
'require_acceptance' => ($category->require_acceptance == '1'),
'item_count' => (int) $category->item_count,
'item_count' => (int) $category->itemCount(),
'assets_count' => (int) $category->assets_count,
'accessories_count' => (int) $category->accessories_count,
'consumables_count' => (int) $category->consumables_count,
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Company;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -3,7 +3,7 @@
namespace App\Http\Transformers;
use App\Models\Asset;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class ComponentsAssetsTransformer
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Component;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Consumable;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Department;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -5,7 +5,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Depreciable;
use App\Models\Depreciation;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class DepreciationsTransformer
+1 -1
View File
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Group;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class GroupsTransformer
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Models\License;
use App\Models\LicenseSeat;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class LicenseSeatsTransformer
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\License;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class LicensesTransformer
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Location;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -63,7 +63,6 @@ class LocationsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => $location->isDeletable(),
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
];
$array += $permissions_array;
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Manufacturer;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Models\PredefinedKit;
use App\Models\SnipeModel;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
/**
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Statuslabel;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class StatuslabelsTransformer
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Supplier;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
+2 -3
View File
@@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
use Gate;
use Illuminate\Database\Eloquent\Collection;
class UsersTransformer
@@ -36,7 +36,6 @@ class UsersTransformer
'name'=> e($user->manager->first_name).' '.e($user->manager->last_name),
] : null,
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
'vip' => ($user->vip == '1') ? true : false,
'phone' => ($user->phone) ? e($user->phone) : null,
'website' => ($user->website) ? e($user->website) : null,
'address' => ($user->address) ? e($user->address) : null,
@@ -57,8 +56,8 @@ class UsersTransformer
'permissions' => $user->decodePermissions(),
'activated' => ($user->activated == '1') ? true : false,
'ldap_import' => ($user->ldap_import == '1') ? true : false,
'two_factor_activated' => ($user->two_factor_active()) ? true : false,
'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false,
'two_factor_optin' => ($user->two_factor_active()) ? true : false,
'assets_count' => (int) $user->assets_count,
'licenses_count' => (int) $user->licenses_count,
'accessories_count' => (int) $user->accessories_count,
+4 -6
View File
@@ -60,7 +60,7 @@ class AssetImporter extends ItemImporter
$asset_tag = Asset::autoincrement_asset();
}
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
$asset = Asset::where(['asset_tag'=> $asset_tag])->first();
if ($asset) {
if (! $this->updating) {
$this->log('A matching Asset '.$asset_tag.' already exists');
@@ -76,12 +76,10 @@ class AssetImporter extends ItemImporter
}
$this->item['notes'] = $this->findCsvMatch($row, 'asset_notes');
$this->item['image'] = $this->findCsvMatch($row, 'image');
$this->item['requestable'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable')) == 1) ? '1' : 0;
$asset->requestable = $this->item['requestable'];
$this->item['requestable'] = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'));
$asset->requestable = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'));
$this->item['warranty_months'] = intval($this->findCsvMatch($row, 'warranty_months'));
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
$this->item['byod'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'byod')) == 1) ? '1' : 0;
// If no status ID is found
if (! array_key_exists('status_id', $this->item) && ! $editingAsset) {
@@ -137,7 +135,7 @@ class AssetImporter extends ItemImporter
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
//-- the class that needs to use it (command importer or GUI importer inside the project).
if (isset($target)) {
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'), null, $asset->notes, $asset->name);
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'));
}
return;
+4 -4
View File
@@ -74,7 +74,7 @@ class ItemImporter extends Importer
$this->item['purchase_date'] = null;
if ($this->findCsvMatch($row, 'purchase_date') != '') {
$this->item['purchase_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'purchase_date')));
$this->item['purchase_date'] = date('Y-m-d 00:00:01', strtotime($this->findCsvMatch($row, 'purchase_date')));
}
$this->item['last_audit_date'] = null;
@@ -90,7 +90,7 @@ class ItemImporter extends Importer
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
$this->item['requestable'] = $this->findCsvMatch($row, 'requestable');
$this->item['user_id'] = $this->user_id;
$this->item['serial'] = $this->findCsvMatch($row, 'serial');
$this->item['serial'] = $this->findCsvMatch($row, 'serial number');
// NO need to call this method if we're running the user import.
// TODO: Merge these methods.
$this->item['checkout_class'] = $this->findCsvMatch($row, 'checkout_class');
@@ -222,11 +222,11 @@ class ItemImporter extends Importer
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
$item['name'] = $asset_model_name;
$item['notes'] = $this->findCsvMatch($row, 'model_notes');
if(!empty($asset_modelNumber)){
$item['model_number'] = $asset_modelNumber;
}
$asset_model->update($item);
$asset_model->save();
$this->log('Asset Model Updated');
-5
View File
@@ -80,11 +80,6 @@ class LicenseImporter extends ItemImporter
$checkout_target = $this->item['checkout_target'];
$asset = Asset::where('asset_tag', $asset_tag)->first();
$targetLicense = $license->freeSeat();
if (is_null($targetLicense)){
return;
}
if ($checkout_target) {
$targetLicense->assigned_to = $checkout_target->id;
$targetLicense->user_id = Auth::id();
-2
View File
@@ -58,8 +58,6 @@ class UserImporter extends ItemImporter
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
$this->item['vip'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
$user_department = $this->findCsvMatch($row, 'department');
if ($this->shouldUpdateField($user_department)) {
+4 -6
View File
@@ -36,10 +36,8 @@
| name | | |
| email | | |
| username | | |
| address | address | User |
| city | city | User |
| state | state | User |
| country | country | User |
| vip | vip | User |
| byod | byod | Asset |
| address | address | User |
| city | city | User |
| state | state | User |
| country | country | User |
-42
View File
@@ -18,9 +18,7 @@ use App\Events\ItemDeclined;
use App\Events\LicenseCheckedIn;
use App\Events\LicenseCheckedOut;
use App\Models\Actionlog;
use App\Models\User;
use App\Models\LicenseSeat;
use App\Events\UserMerged;
class LogListener
{
@@ -89,43 +87,6 @@ class LogListener
$logaction->save();
}
public function onUserMerged(UserMerged $event)
{
$to_from_array = [
'to_id' => $event->merged_to->id,
'to_username' => $event->merged_to->username,
'from_id' => $event->merged_from->id,
'from_username' => $event->merged_from->username,
];
// Add a record to the users being merged FROM
\Log::debug('Users merged: '.$event->merged_from->id .' ('.$event->merged_from->username.') merged into '. $event->merged_to->id. ' ('.$event->merged_to->username.')');
$logaction = new Actionlog();
$logaction->item_id = $event->merged_from->id;
$logaction->item_type = User::class;
$logaction->target_id = $event->merged_to->id;
$logaction->target_type = User::class;
$logaction->action_type = 'merged';
$logaction->note = trans('general.merged_log_this_user_from', $to_from_array);
$logaction->user_id = $event->admin->id;
$logaction->save();
// Add a record to the users being merged TO
$logaction = new Actionlog();
$logaction->target_id = $event->merged_from->id;
$logaction->target_type = User::class;
$logaction->item_id = $event->merged_to->id;
$logaction->item_type = User::class;
$logaction->action_type = 'merged';
$logaction->note = trans('general.merged_log_this_user_into', $to_from_array);
$logaction->user_id = $event->admin->id;
$logaction->save();
}
/**
* Register the listeners for the subscriber.
*
@@ -138,7 +99,6 @@ class LogListener
'CheckoutableCheckedOut',
'CheckoutAccepted',
'CheckoutDeclined',
'UserMerged',
];
foreach ($list as $event) {
@@ -148,6 +108,4 @@ class LogListener
);
}
}
}
+17 -8
View File
@@ -63,7 +63,6 @@ class Accessory extends SnipeModel
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_date' => 'date_format:Y-m-d|nullable',
];
@@ -328,13 +327,23 @@ class Accessory extends SnipeModel
return null;
}
/**
* Check how many items within an accessory are checked out
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0]
* @return int
*/
public function numCheckedOut()
{
$checkedout = 0;
$checkedout = $this->users->count();
return $checkedout;
}
/**
* Check how many items of an accessory remain.
*
* In order to use this model method, you MUST call withCount('users as users_count')
* on the eloquent query in the controller, otherwise $this->>users_count will be null and
* bad things happen.
* Check how many items of an accessory remain
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
@@ -342,11 +351,11 @@ class Accessory extends SnipeModel
*/
public function numRemaining()
{
$checkedout = $this->users_count;
$checkedout = $this->users->count();
$total = $this->qty;
$remaining = $total - $checkedout;
return (int) $remaining;
return $remaining;
}
/**
+34 -54
View File
@@ -34,9 +34,9 @@ class Asset extends Depreciable
use CompanyableTrait;
use HasFactory, Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait, UniqueSerialTrait;
public const LOCATION = 'location';
public const ASSET = 'asset';
public const USER = 'user';
const LOCATION = 'location';
const ASSET = 'asset';
const USER = 'user';
use Acceptable;
@@ -70,22 +70,31 @@ class Asset extends Depreciable
*/
protected $injectUniqueIdentifier = true;
// We set these as protected dates so that they will be easily accessible via Carbon
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
'purchase_date',
'last_checkout',
'expected_checkin',
'last_audit_date',
'next_audit_date'
];
protected $casts = [
'purchase_date' => 'date',
'purchase_date' => 'datetime',
'last_checkout' => 'datetime',
'expected_checkin' => 'date',
'expected_checkin' => 'datetime',
'last_audit_date' => 'datetime',
'next_audit_date' => 'date',
'next_audit_date' => 'datetime',
'model_id' => 'integer',
'status_id' => 'integer',
'company_id' => 'integer',
'location_id' => 'integer',
'rtd_company_id' => 'integer',
'supplier_id' => 'integer',
'byod' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
protected $rules = [
@@ -95,16 +104,18 @@ class Asset extends Depreciable
'company_id' => 'integer|nullable',
'warranty_months' => 'numeric|nullable|digits_between:0,240',
'physical' => 'numeric|max:1|nullable',
'last_checkout' => 'date_format:Y-m-d H:i:s|nullable',
'expected_checkin' => 'date|nullable',
'checkout_date' => 'date|max:10|min:10|nullable',
'checkin_date' => 'date|max:10|min:10|nullable',
'supplier_id' => 'exists:suppliers,id|numeric|nullable',
'location_id' => 'exists:locations,id|nullable',
'rtd_location_id' => 'exists:locations,id|nullable',
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
'purchase_date' => 'date|date_format:Y-m-d|nullable',
'status' => 'integer',
'serial' => 'unique_serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'next_audit_date' => 'date|nullable',
'last_audit_date' => 'date|nullable',
'supplier_id' => 'exists:suppliers,id|nullable',
'asset_eol_date' => 'date|max:10|min:10|nullable',
];
/**
@@ -133,10 +144,6 @@ class Asset extends Depreciable
'requestable',
'last_checkout',
'expected_checkin',
'byod',
'asset_eol_date',
'last_audit_date',
'next_audit_date',
];
use Searchable;
@@ -159,7 +166,6 @@ class Asset extends Depreciable
'expected_checkin',
'next_audit_date',
'last_audit_date',
'asset_eol_date',
];
/**
@@ -173,19 +179,11 @@ class Asset extends Depreciable
'company' => ['name'],
'defaultLoc' => ['name'],
'location' => ['name'],
'model' => ['name', 'model_number', 'eol'],
'model' => ['name', 'model_number'],
'model.category' => ['name'],
'model.manufacturer' => ['name'],
];
// To properly set the expected checkin as Y-m-d
public function setExpectedCheckinAttribute($value)
{
if ($value == '') {
$value = null;
}
$this->attributes['expected_checkin'] = $value;
}
/**
* This handles the custom field validation for assets
@@ -317,10 +315,14 @@ class Asset extends Depreciable
}
$this->last_checkout = $checkout_at;
$this->name = $name;
$this->assignedTo()->associate($target);
if ($name != null) {
$this->name = $name;
}
if ($location != null) {
$this->location_id = $location;
} else {
@@ -537,28 +539,6 @@ class Asset extends Depreciable
return strtolower(class_basename($this->assigned_type));
}
/**
* This is annoying, but because we don't say "assets" in our route names, we have to make an exception here
* @todo - normalize the route names - API endpoint URLS can stay the same
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.1.0]
* @return string
*/
public function targetShowRoute()
{
$route = str_plural($this->assignedType());
if ($route=='assets') {
return 'hardware';
}
return $route;
}
/**
* Get the asset's location based on default RTD location
*
@@ -1655,9 +1635,9 @@ class Asset extends Depreciable
*/
public function scopeOrderManufacturer($query, $order)
{
return $query->join('models as order_asset_model', 'assets.model_id', '=', 'order_asset_model.id')
->join('manufacturers as manufacturer_order', 'order_asset_model.manufacturer_id', '=', 'manufacturer_order.id')
->orderBy('manufacturer_order.name', $order);
return $query->join('models', 'assets.model_id', '=', 'models.id')
->join('manufacturers', 'models.manufacturer_id', '=', 'manufacturers.id')
->orderBy('manufacturers.name', $order);
}
/**
+3 -32
View File
@@ -10,7 +10,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate;
use Watson\Validating\ValidatingTrait;
use App\Helpers\Helper;
use Illuminate\Support\Str;
/**
* Model for Categories. Categories are a higher-level group
@@ -98,7 +97,6 @@ class Category extends SnipeModel
*/
public function isDeletable()
{
return Gate::allows('delete', $this)
&& ($this->itemCount() == 0);
}
@@ -152,10 +150,7 @@ class Category extends SnipeModel
}
/**
* Get the number of items in the category. This should NEVER be used in
* a collection of categories, as you'll end up with an n+1 query problem.
*
* It should only be used in a single category context.
* Get the number of items in the category
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
@@ -163,11 +158,6 @@ class Category extends SnipeModel
*/
public function itemCount()
{
if (isset($this->{Str::plural($this->category_type).'_count'})) {
return $this->{Str::plural($this->category_type).'_count'};
}
switch ($this->category_type) {
case 'asset':
return $this->assets()->count();
@@ -179,10 +169,9 @@ class Category extends SnipeModel
return $this->consumables()->count();
case 'license':
return $this->licenses()->count();
default:
return 0;
}
return '0';
}
/**
@@ -194,25 +183,7 @@ class Category extends SnipeModel
*/
public function assets()
{
return $this->hasManyThrough(Asset::class, \App\Models\AssetModel::class, 'category_id', 'model_id');
}
/**
* Establishes the category -> assets relationship but also takes into consideration
* the setting to show archived in lists.
*
* We could have complicated the assets() method above, but keeping this separate
* should give us more flexibility if we need to return actually archived assets
* by their category.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.1.0]
* @see \App\Models\Asset::scopeAssetsForShow()
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function showableAssets()
{
return $this->hasManyThrough(Asset::class, \App\Models\AssetModel::class, 'category_id', 'model_id')->AssetsForShow();
return $this->hasManyThrough(\App\Models\Asset::class, \App\Models\AssetModel::class, 'category_id', 'model_id');
}
/**
+3 -10
View File
@@ -16,19 +16,12 @@ class CheckoutAcceptance extends Model
'declined_at' => 'datetime',
];
/**
* Get the mail recipient from the config
*
* @return mixed|string|null
*/
public function routeNotificationForMail()
// Get the mail recipient from the config
public function routeNotificationForMail(): string
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
$recipients_string = explode(',', Setting::getSettings()->alert_email);
$recipients = array_map('trim', $recipients_string);
return array_filter($recipients);
return (config('mail.reply_to.address')) ? config('mail.reply_to.address') : '' ;
}
/**
+1 -1
View File
@@ -35,7 +35,7 @@ class Component extends SnipeModel
'category_id' => 'required|integer|exists:categories,id',
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_date' => 'date_format:Y-m-d|nullable',
'purchase_date' => 'date|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
];

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