Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bf6c48d695 | |||
| 8428b2a04a | |||
| 71e745d966 | |||
| a3a786f2af | |||
| 0086adab86 | |||
| 0f91e898fd | |||
| 636da2ab5e | |||
| 4f182c0a50 | |||
| a384d0173a | |||
| 427f8b1522 | |||
| 8902145288 | |||
| 8b52bad16f | |||
| daed0b60bc | |||
| 4654f7aa37 | |||
| 70e87dad1c | |||
| ba8d8a6f05 | |||
| 605d267fe8 | |||
| 8f2a17585e | |||
| 51424d01a9 | |||
| f5ff9b2208 | |||
| a9c7dbd17a | |||
| 09fdc946a0 | |||
| 31f1bce16b | |||
| 2f3ddaec20 | |||
| 7cd37e6e95 | |||
| a938009074 | |||
| 21d08ff742 | |||
| da8b41b12a | |||
| 6e031727fa | |||
| 381890b578 | |||
| 71fa6d765f | |||
| 9793130f6c | |||
| aadfa9aa9c | |||
| 645bba96cd |
@@ -2961,15 +2961,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Singrity",
|
||||
"name": "Bogdan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/58479551?v=4",
|
||||
"profile": "http://@singrity",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
version: 1
|
||||
|
||||
environment:
|
||||
php: 8.0
|
||||
node: 12
|
||||
|
||||
services:
|
||||
- mysql: 5.7
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches: .*
|
||||
|
||||
pipeline:
|
||||
- name: Setup
|
||||
cmd: |
|
||||
cp -v .env.testing.example .env
|
||||
cp -v .env.testing.example .env.testing
|
||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Generate Key
|
||||
cmd: |
|
||||
php artisan key:generate --force
|
||||
|
||||
- name: Passport Keys
|
||||
cmd: |
|
||||
php artisan passport:keys
|
||||
|
||||
- name: Run Migrations
|
||||
cmd: |
|
||||
php artisan migrate --force
|
||||
|
||||
- name: PHPUnit Unit Tests
|
||||
cmd: |
|
||||
php artisan test --testsuite Unit
|
||||
|
||||
- name: PHPUnit Feature Tests
|
||||
cmd: |
|
||||
php artisan test --testsuite Feature
|
||||
@@ -18,5 +18,5 @@ importer: ["/app/Importer/*","/app/Http/Livewire/Importer.php", "resources/views
|
||||
cli / artisan: ["/app/Console/*"]
|
||||
LDAP: ["*Ldap*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
|
||||
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
|
||||
tests: ["/tests/*", "/database/factories/*", "/stubs"]
|
||||
tests: ["/tests/*", "/stubs"]
|
||||
config: .github
|
||||
|
||||
@@ -2,6 +2,5 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "develop"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
language: [ 'javascript' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Crowdin push
|
||||
uses: crowdin/github-action@v1
|
||||
|
||||
@@ -32,7 +32,6 @@ jobs:
|
||||
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
|
||||
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
|
||||
type=ref,event=tag,suffix=-alpine
|
||||
type=semver,pattern=v{{major}}-latest-alpine
|
||||
# Define default tag "flavor" for docker/metadata-action per
|
||||
# https://github.com/docker/metadata-action#flavor-input
|
||||
# We turn off 'latest' tag by default.
|
||||
@@ -42,17 +41,17 @@ jobs:
|
||||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
@@ -64,7 +63,7 @@ jobs:
|
||||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
@@ -73,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@v5
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.alpine
|
||||
|
||||
@@ -32,7 +32,6 @@ jobs:
|
||||
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern=v{{major}}-latest
|
||||
# Define default tag "flavor" for docker/metadata-action per
|
||||
# https://github.com/docker/metadata-action#flavor-input
|
||||
# We turn off 'latest' tag by default.
|
||||
@@ -42,17 +41,17 @@ jobs:
|
||||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
@@ -64,7 +63,7 @@ jobs:
|
||||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
@@ -73,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@v5
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
coverage: none
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get Composer Cache Directory
|
||||
id: composer-cache
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeitapp) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
 [](https://crowdin.com/project/snipe-it) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeitapp) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
||||
@@ -145,7 +145,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<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/5731963?v=4" width="110px;"/><br /><sub>dboth</sub>](http://dboth.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dboth "Code") | [<img src="https://avatars.githubusercontent.com/u/87536651?v=4" width="110px;"/><br /><sub>Zachary Fleck</sub>](https://github.com/zacharyfleck)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zacharyfleck "Code") | [<img src="https://avatars.githubusercontent.com/u/74609912?v=4" width="110px;"/><br /><sub>VIKAAS-A</sub>](https://github.com/vikaas-cyper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vikaas-cyper "Code") | [<img src="https://avatars.githubusercontent.com/u/88882041?v=4" width="110px;"/><br /><sub>Abdul Kareem</sub>](https://github.com/ak-piracha)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ak-piracha "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [<img src="https://avatars.githubusercontent.com/u/58479551?v=4" width="110px;"/><br /><sub>Bogdan</sub>](http://@singrity)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -180,6 +180,10 @@ class LdapSync extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/* Create user account entries in Snipe-IT */
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
|
||||
$pass = bcrypt($tmp_pass);
|
||||
|
||||
$manager_cache = [];
|
||||
|
||||
if($ldap_default_group != null) {
|
||||
@@ -225,7 +229,7 @@ class LdapSync extends Command
|
||||
} else {
|
||||
// Creating a new user.
|
||||
$user = new User;
|
||||
$user->password = $user->noPassword();
|
||||
$user->password = $pass;
|
||||
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
||||
$item['createorupdate'] = 'created';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/*********************
|
||||
* These two helper methods are more designed for being re-used with the new HasCustomFields Trait
|
||||
*
|
||||
* The 'transform' method is designed for BlahTransformer things that need to return custom field values.
|
||||
*
|
||||
* The 'present' method is designed for when you're trying to generate fieldlists for use in Bootstrap tables
|
||||
* - typically the 'dataTableLayout' method
|
||||
*
|
||||
*********************/
|
||||
class CustomFieldHelper {
|
||||
|
||||
static function transform($fieldset, $item) {
|
||||
if ($fieldset && ($fieldset->fields->count() > 0)) {
|
||||
$fields_array = [];
|
||||
|
||||
foreach ($fieldset->fields as $field) {
|
||||
if ($field->isFieldDecryptable($item->{$field->db_column})) {
|
||||
$decrypted = Helper::gracefulDecrypt($field, $item->{$field->db_column});
|
||||
$value = (Gate::allows('assets.view.encrypted_custom_fields')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
|
||||
if ($field->format == 'DATE'){
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
} else {
|
||||
$value = strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
}
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
|
||||
} else {
|
||||
$value = $item->{$field->db_column};
|
||||
|
||||
if (($field->format == 'DATE') && (!is_null($value)) && ($value!='')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
}
|
||||
|
||||
return $fields_array;
|
||||
}
|
||||
} else {
|
||||
return new \stdClass; // HACK to force generation of empty object instead of empty list
|
||||
}
|
||||
}
|
||||
|
||||
static function present($field) {
|
||||
return [
|
||||
'field' => 'custom_fields.'.$field->db_column,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => $field->name,
|
||||
'formatter'=> 'customFieldsFormatter',
|
||||
'escape' => true,
|
||||
'class' => ($field->field_encrypted == '1') ? 'css-padlock' : '',
|
||||
'visible' => ($field->show_in_listview == '1') ? true : false,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -575,6 +575,17 @@ class Helper
|
||||
return $customfields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the different types of custom fields there are
|
||||
* TODO - how to make this more general? Or more useful? or more dynamic?
|
||||
* idea - key of classname, *value* of trans? (thus having to make this a method, which is fine)
|
||||
*/
|
||||
static $itemtypes_having_custom_fields = [
|
||||
0 => \App\Models\Asset::class,
|
||||
1 => \App\Models\User::class,
|
||||
// 2 => \App\Models\Accessory::class
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the list of custom field formats in an array to make a dropdown menu
|
||||
*
|
||||
|
||||
@@ -146,8 +146,9 @@ class AccessoriesFilesController extends Controller
|
||||
$this->authorize('view', $accessory);
|
||||
$this->authorize('accessories.files', $accessory);
|
||||
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) {
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/users/message.log_record_not_found'));
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/accessories/'.$log->filename;
|
||||
|
||||
@@ -46,7 +46,6 @@ class AssetModelsController extends Controller
|
||||
'requestable',
|
||||
'assets_count',
|
||||
'category',
|
||||
'fieldset',
|
||||
];
|
||||
|
||||
$assetmodels = AssetModel::select([
|
||||
@@ -66,7 +65,7 @@ class AssetModelsController extends Controller
|
||||
'models.deleted_at',
|
||||
'models.updated_at',
|
||||
])
|
||||
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues')
|
||||
->with('category', 'depreciation', 'manufacturer')
|
||||
->withCount('assets as assets_count');
|
||||
|
||||
if ($request->input('status')=='deleted') {
|
||||
@@ -95,9 +94,6 @@ class AssetModelsController extends Controller
|
||||
case 'category':
|
||||
$assetmodels->OrderCategory($order);
|
||||
break;
|
||||
case 'fieldset':
|
||||
$assetmodels->OrderFieldset($order);
|
||||
break;
|
||||
default:
|
||||
$assetmodels->orderBy($sort, $order);
|
||||
break;
|
||||
|
||||
@@ -110,7 +110,7 @@ class AssetsController extends Controller
|
||||
$filter = json_decode($request->input('filter'), true);
|
||||
}
|
||||
|
||||
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
|
||||
$all_custom_fields = CustomField::where('type', Asset::class); //used as a 'cache' of custom fields throughout this page load
|
||||
foreach ($all_custom_fields as $field) {
|
||||
$allowed_columns[] = $field->db_column_name();
|
||||
}
|
||||
@@ -346,7 +346,7 @@ class AssetsController extends Controller
|
||||
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $assets->count()) ? $assets->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$total = $assets->count();
|
||||
@@ -573,42 +573,8 @@ class AssetsController extends Controller
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
$asset->customFill($request, Auth::user(), true);
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
// Set the field value based on what was sent in the request
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if ($field_val == null) {
|
||||
\Log::debug('Field value for '.$field->db_column.' is null');
|
||||
$field_val = $field->defaultValue($request->get('model_id'));
|
||||
\Log::debug('Use the default fieldset value of '.$field->defaultValue($request->get('model_id')));
|
||||
}
|
||||
|
||||
// if the field is set to encrypted, make sure we encrypt the value
|
||||
if ($field->field_encrypted == '1') {
|
||||
\Log::debug('This model field is encrypted in this fieldset.');
|
||||
|
||||
if (Gate::allows('admin')) {
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if (($field_val == null) && ($request->has('model_id') != '')) {
|
||||
$field_val = \Crypt::encrypt($field->defaultValue($request->get('model_id')));
|
||||
} else {
|
||||
$field_val = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset->save()) {
|
||||
if ($request->get('assigned_user')) {
|
||||
@@ -668,21 +634,7 @@ class AssetsController extends Controller
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
// Update custom fields
|
||||
if (($model = AssetModel::find($asset->model_id)) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$asset->customFill($request,Auth::user());
|
||||
|
||||
if ($asset->save()) {
|
||||
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
|
||||
|
||||
@@ -92,7 +92,7 @@ class CategoriesController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $categories->count()) ? $categories->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $categories->count()) ? $categories->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -56,7 +56,7 @@ class CompaniesController extends Controller
|
||||
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $companies->count()) ? $companies->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $companies->count()) ? $companies->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class ComponentsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $components->count()) ? $components->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $components->count()) ? $components->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
@@ -263,7 +263,7 @@ class ComponentsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure there is at least one available to checkout
|
||||
if ($component->numRemaining() < $request->get('assigned_qty')) {
|
||||
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')])));
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class ConsumablesController extends Controller
|
||||
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$allowed_columns = ['id', 'name', 'order_number', 'min_amt', 'purchase_date', 'purchase_cost', 'company', 'category', 'model_number', 'item_no', 'manufacturer', 'location', 'qty', 'image'];
|
||||
|
||||
@@ -35,7 +35,7 @@ class CustomFieldsetsController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$this->authorize('index', CustomField::class);
|
||||
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
|
||||
$fieldsets = CustomFieldset::withCount('fields as fields_count')->get();
|
||||
|
||||
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class CustomFieldsetsController extends Controller
|
||||
$this->authorize('delete', CustomField::class);
|
||||
$fieldset = CustomFieldset::findOrFail($id);
|
||||
|
||||
$modelsCount = $fieldset->models->count();
|
||||
$modelsCount = $fieldset->customizables()->count();
|
||||
$fieldsCount = $fieldset->fields->count();
|
||||
|
||||
if (($modelsCount > 0) || ($fieldsCount > 0)) {
|
||||
|
||||
@@ -27,7 +27,7 @@ class DepartmentsController extends Controller
|
||||
$this->authorize('view', Department::class);
|
||||
$allowed_columns = ['id', 'name', 'image', 'users_count'];
|
||||
|
||||
$departments = Department::select(
|
||||
$departments = Company::scopeCompanyables(Department::select(
|
||||
'departments.id',
|
||||
'departments.name',
|
||||
'departments.phone',
|
||||
@@ -37,8 +37,8 @@ class DepartmentsController extends Controller
|
||||
'departments.manager_id',
|
||||
'departments.created_at',
|
||||
'departments.updated_at',
|
||||
'departments.image'
|
||||
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
|
||||
'departments.image'),
|
||||
"company_id", "departments")->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$departments = $departments->TextSearch($request->input('search'));
|
||||
@@ -61,7 +61,7 @@ class DepartmentsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $departments->count()) ? $departments->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $departments->count()) ? $departments->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -29,7 +29,7 @@ class DepreciationsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $depreciations->count()) ? $depreciations->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $depreciations->count()) ? $depreciations->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -36,7 +36,7 @@ class GroupsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $groups->count()) ? $groups->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $groups->count()) ? $groups->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
@@ -63,7 +63,7 @@ class GroupsController extends Controller
|
||||
$group = new Group;
|
||||
|
||||
$group->name = $request->input('name');
|
||||
$group->permissions = json_encode($request->input('permissions')); // Todo - some JSON validation stuff here
|
||||
$group->permissions = $request->input('permissions'); // Todo - some JSON validation stuff here
|
||||
|
||||
if ($group->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $group, trans('admin/groups/message.create.success')));
|
||||
|
||||
@@ -41,7 +41,7 @@ class LicenseSeatsController extends Controller
|
||||
$total = $seats->count();
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $seats->count()) ? $seats->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $seats->count()) ? $seats->count() : abs($request->input('offset'));
|
||||
|
||||
if ($offset >= $total ){
|
||||
$offset = 0;
|
||||
|
||||
@@ -95,7 +95,7 @@ class LicensesController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -81,7 +81,7 @@ class LocationsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -62,7 +62,7 @@ class ManufacturersController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $manufacturers->count()) ? $manufacturers->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -30,7 +30,7 @@ class PredefinedKitsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $kits->count()) ? $kits->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $kits->count()) ? $kits->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'desc' ? 'desc' : 'asc';
|
||||
|
||||
@@ -56,7 +56,7 @@ class ReportsController extends Controller
|
||||
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $actionlogs->count()) ? $actionlogs->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $actionlogs->count()) ? $actionlogs->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
|
||||
@@ -52,7 +52,7 @@ class StatuslabelsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $statuslabels->count()) ? $statuslabels->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $statuslabels->count()) ? $statuslabels->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -94,7 +94,7 @@ class SuppliersController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $suppliers->count()) ? $suppliers->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $suppliers->count()) ? $suppliers->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
@@ -13,6 +13,7 @@ use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Http\Transformers\UsersTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CurrentInventory;
|
||||
@@ -36,7 +37,7 @@ class UsersController extends Controller
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
|
||||
$users = User::select([
|
||||
$allowed_columns = [
|
||||
'users.activated',
|
||||
'users.created_by',
|
||||
'users.address',
|
||||
@@ -73,7 +74,12 @@ class UsersController extends Controller
|
||||
'users.vip',
|
||||
'users.autoassign_licenses',
|
||||
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
|
||||
];
|
||||
|
||||
foreach(CustomField::where('type', User::class)->get() as $field) {
|
||||
$allowed_columns[] = $field->db_column_name();
|
||||
}
|
||||
$users = User::select()->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');
|
||||
|
||||
|
||||
@@ -192,7 +198,7 @@ class UsersController extends Controller
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
|
||||
@@ -363,15 +369,13 @@ class UsersController extends Controller
|
||||
$user->permissions = $permissions_array;
|
||||
}
|
||||
|
||||
//
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->get('password'));
|
||||
} else {
|
||||
$user->password = $user->noPassword();
|
||||
}
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
$user->password = bcrypt($request->get('password', $tmp_pass));
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
|
||||
|
||||
$user->customFill($request,Auth::user());
|
||||
|
||||
if ($user->save()) {
|
||||
if ($request->filled('groups')) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
@@ -462,7 +466,9 @@ class UsersController extends Controller
|
||||
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
|
||||
|
||||
$user->customFill($request,Auth::user());
|
||||
|
||||
if ($user->save()) {
|
||||
|
||||
// Sync group memberships:
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace App\Http\Controllers;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\DefaultValuesForCustomFields;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
@@ -161,7 +161,7 @@ class AssetModelsController extends Controller
|
||||
$model->notes = $request->input('notes');
|
||||
$model->requestable = $request->input('requestable', '0');
|
||||
|
||||
$this->removeCustomFieldsDefaultValues($model);
|
||||
DefaultValuesForCustomFields::forPivot($model, Asset::class)->delete();
|
||||
|
||||
if ($request->input('fieldset_id') == '') {
|
||||
$model->fieldset_id = null;
|
||||
@@ -174,15 +174,8 @@ class AssetModelsController extends Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($model->save()) {
|
||||
if ($model->wasChanged('eol')) {
|
||||
$newEol = $model->eol;
|
||||
$model->assets()->whereNotNull('purchase_date')->where('eol_explicit', false)
|
||||
->update(['asset_eol_date' => DB::raw('DATE_ADD(purchase_date, INTERVAL ' . $newEol . ' MONTH)')]);
|
||||
}
|
||||
return redirect()->route('models.index')->with('success', trans('admin/models/message.update.success'));
|
||||
}
|
||||
|
||||
@@ -459,7 +452,7 @@ class AssetModelsController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default values to a model (as long as they are truthy)
|
||||
* Adds default values to a model (as long as they are truthy) (does this mean I cannot set a default value of 0?)
|
||||
*
|
||||
* @param AssetModel $model
|
||||
* @param array $defaultValues
|
||||
@@ -494,22 +487,12 @@ class AssetModelsController extends Controller
|
||||
}
|
||||
|
||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||
if(is_array($defaultValue)){
|
||||
$model->defaultValues()->attach($customFieldId, ['default_value' => implode(', ', $defaultValue)]);
|
||||
}elseif ($defaultValue) {
|
||||
$model->defaultValues()->attach($customFieldId, ['default_value' => $defaultValue]);
|
||||
if(is_array($defaultValue)) {
|
||||
$defaultValue = implode(', ', $defaultValue);
|
||||
}
|
||||
DefaultValuesForCustomFields::updateOrCreate(['custom_field_id' => $customFieldId,'item_pivot_id' => $model->id], ['default_value' => $defaultValue]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all default values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function removeCustomFieldsDefaultValues(AssetModel $model)
|
||||
{
|
||||
$model->defaultValues()->detach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +91,7 @@ class AssetCheckoutController extends Controller
|
||||
|
||||
$settings = \App\Models\Setting::getSettings();
|
||||
|
||||
// We have to check whether $target->company_id is null here since locations don't have a company yet
|
||||
if (($settings->full_multiple_companies_support) && ((!is_null($target->company_id)) && (!is_null($asset->company_id)))) {
|
||||
if ($settings->full_multiple_companies_support){
|
||||
if ($target->company_id != $asset->company_id){
|
||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class AssetFilesController extends Controller
|
||||
if (isset($asset->id)) {
|
||||
$this->authorize('view', $asset);
|
||||
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Actionlog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CheckoutRequest;
|
||||
@@ -15,18 +14,26 @@ use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\View\Label;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Input;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use League\Csv\Reader;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use League\Csv\Statement;
|
||||
use Paginator;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Slack;
|
||||
use Str;
|
||||
use TCPDF;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* This class controls all actions related to assets for
|
||||
@@ -157,29 +164,7 @@ class AssetsController extends Controller
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$asset->customFill($request, Auth::user()); // Update custom fields in the database.
|
||||
|
||||
// Validate the asset before saving
|
||||
if ($asset->isValid() && $asset->save()) {
|
||||
@@ -291,10 +276,10 @@ class AssetsController extends Controller
|
||||
/**
|
||||
* Validate and process asset edit form.
|
||||
*
|
||||
* @param int $assetId
|
||||
* @return \Illuminate\Http\RedirectResponse|Redirect
|
||||
*@since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $assetId
|
||||
* @since [v1.0]
|
||||
* @return Redirect
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, $assetId = null)
|
||||
{
|
||||
@@ -308,23 +293,9 @@ class AssetsController extends Controller
|
||||
$asset->status_id = $request->input('status_id', null);
|
||||
$asset->warranty_months = $request->input('warranty_months', null);
|
||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && $asset->model->eol) {
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
} elseif ($request->filled('asset_eol_date')) {
|
||||
$asset->asset_eol_date = $request->input('asset_eol_date', null);
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if($asset->model->eol) {
|
||||
if($months != $asset->model->eol) {
|
||||
$asset->eol_explicit = true;
|
||||
} else {
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
} else {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
}
|
||||
$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);
|
||||
|
||||
@@ -349,7 +320,7 @@ class AssetsController extends Controller
|
||||
unlink(public_path().'/uploads/assets/'.$asset->image);
|
||||
$asset->image = '';
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e);
|
||||
\Log::info($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,9 +348,9 @@ class AssetsController extends Controller
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -427,7 +398,7 @@ class AssetsController extends Controller
|
||||
try {
|
||||
Storage::disk('public')->delete('assets'.'/'.$asset->image);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
\Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,7 +513,7 @@ class AssetsController extends Controller
|
||||
|
||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||
} catch (\Exception $e) {
|
||||
Log::debug('The barcode format is invalid.');
|
||||
\Log::debug('The barcode format is invalid.');
|
||||
|
||||
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
|
||||
}
|
||||
@@ -863,7 +834,7 @@ class AssetsController extends Controller
|
||||
'next_audit_date' => 'date|nullable',
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
@@ -880,7 +851,7 @@ class AssetsController extends Controller
|
||||
// Check to see if they checked the box to update the physical location,
|
||||
// not just note it in the audit notes
|
||||
if ($request->input('update_location') == '1') {
|
||||
Log::debug('update location in audit');
|
||||
\Log::debug('update location in audit');
|
||||
$asset->location_id = $request->input('location_id');
|
||||
}
|
||||
|
||||
|
||||
@@ -191,11 +191,9 @@ class LoginController extends Controller
|
||||
|
||||
$ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user);
|
||||
|
||||
$user->password = $user->noPassword();
|
||||
if (Setting::getSettings()->ldap_pw_sync=='1') {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
$user->email = $ldap_attr['email'];
|
||||
$user->first_name = $ldap_attr['firstname'];
|
||||
$user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc.
|
||||
|
||||
@@ -56,11 +56,10 @@ class ComponentCheckinController extends Controller
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(Request $request, $component_asset_id, $backto = null)
|
||||
public function store(Request $request, $component_asset_id)
|
||||
{
|
||||
if ($component_assets = DB::table('components_assets')->find($component_asset_id)) {
|
||||
if (is_null($component = Component::find($component_assets->component_id))) {
|
||||
|
||||
return redirect()->route('components.index')->with('error',
|
||||
trans('admin/components/message.not_found'));
|
||||
}
|
||||
@@ -96,10 +95,6 @@ class ComponentCheckinController extends Controller
|
||||
$asset = Asset::find($component_assets->asset_id);
|
||||
|
||||
event(new CheckoutableCheckedIn($component, $asset, Auth::user(), $request->input('note'), Carbon::now()));
|
||||
if($backto == 'asset'){
|
||||
return redirect()->route('hardware.view', $asset->id)->with('success',
|
||||
trans('admin/components/message.checkin.success'));
|
||||
}
|
||||
|
||||
return redirect()->route('components.index')->with('success',
|
||||
trans('admin/components/message.checkin.success'));
|
||||
|
||||
@@ -142,7 +142,7 @@ class ComponentsFilesController extends Controller
|
||||
$this->authorize('view', $component);
|
||||
$this->authorize('components.files', $component);
|
||||
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) {
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class ConsumablesFilesController extends Controller
|
||||
$this->authorize('view', $consumable);
|
||||
$this->authorize('consumables.files', $consumable);
|
||||
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) {
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ use App\Helpers\Helper;
|
||||
use App\Http\Requests\CustomFieldRequest;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Redirect;
|
||||
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Custom Asset Fields for
|
||||
* the Snipe-IT Asset Management application.
|
||||
@@ -21,6 +23,7 @@ use Redirect;
|
||||
*/
|
||||
class CustomFieldsController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns a view with a listing of custom fields.
|
||||
*
|
||||
@@ -29,12 +32,16 @@ class CustomFieldsController extends Controller
|
||||
* @return \Illuminate\Support\Facades\View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', CustomField::class);
|
||||
if ( $request->input('tab') == 1 ) {
|
||||
// Users section, make sure to auto-create the first fieldset if so
|
||||
CustomFieldset::firstOrCreate(['type' => Helper::$itemtypes_having_custom_fields[1]], ['name' => 'default']);
|
||||
}
|
||||
|
||||
$fieldsets = CustomFieldset::with('fields', 'models')->get();
|
||||
$fields = CustomField::with('fieldset')->get();
|
||||
$fieldsets = CustomFieldset::with('fields')->where("type", Helper::$itemtypes_having_custom_fields[$request->get('tab',0)])->get(); //cannot eager-load 'customizable' because it's not a relation
|
||||
$fields = CustomField::with('fieldset')->where("type", Helper::$itemtypes_having_custom_fields[$request->get('tab',0)])->get();
|
||||
|
||||
return view('custom_fields.index')->with('custom_fieldsets', $fieldsets)->with('custom_fields', $fields);
|
||||
}
|
||||
@@ -67,7 +74,7 @@ class CustomFieldsController extends Controller
|
||||
public function create(Request $request)
|
||||
{
|
||||
$this->authorize('create', CustomField::class);
|
||||
$fieldsets = CustomFieldset::get();
|
||||
$fieldsets = CustomFieldset::where('type', Helper::$itemtypes_having_custom_fields[$request->get('tab')])->get();
|
||||
|
||||
return view('custom_fields.fields.edit', [
|
||||
'predefinedFormats' => Helper::predefined_formats(),
|
||||
@@ -110,8 +117,10 @@ class CustomFieldsController extends Controller
|
||||
"display_in_user_view" => $display_in_user_view,
|
||||
"auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0),
|
||||
"show_in_listview" => $request->get("show_in_listview", 0),
|
||||
"user_id" => Auth::id()
|
||||
"user_id" => Auth::id(),
|
||||
]);
|
||||
// not mass-assignable; must be manual
|
||||
$field->type = Helper::$itemtypes_having_custom_fields[$request->get('tab')];
|
||||
|
||||
|
||||
if ($request->filled('custom_format')) {
|
||||
@@ -124,14 +133,17 @@ class CustomFieldsController extends Controller
|
||||
|
||||
// Sync fields with fieldsets
|
||||
$fieldset_array = $request->input('associate_fieldsets');
|
||||
if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) {
|
||||
if ($request->get('tab') == 1 ) {
|
||||
$fieldset_array = [CustomFieldset::firstOrCreate(['type' => User::class],['name' => 'default'])->id => true];
|
||||
}
|
||||
if (($request->has('associate_fieldsets') || $request->get('tab') == 1) && (is_array($fieldset_array))) {
|
||||
$field->fieldset()->sync(array_keys($fieldset_array));
|
||||
} else {
|
||||
$field->fieldset()->sync([]);
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.create.success'));
|
||||
return redirect()->route('fields.index',['tab' => $request->get('tab',0)])->with('success', trans('admin/custom_fields/message.field.create.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('selected_fieldsets', $request->input('associate_fieldsets'))->withInput()
|
||||
@@ -184,12 +196,17 @@ class CustomFieldsController extends Controller
|
||||
if ($field = CustomField::find($field_id)) {
|
||||
$this->authorize('delete', $field);
|
||||
|
||||
if ($field->type == User::class) {
|
||||
$field->fieldset()->detach(); // remove from 'default' group (and others, if they exist in the future!)
|
||||
}
|
||||
if (($field->fieldset) && ($field->fieldset->count() > 0)) {
|
||||
return redirect()->back()->withErrors(['message' => 'Field is in-use']);
|
||||
}
|
||||
$type = $field->type;
|
||||
$field->delete();
|
||||
return redirect()->route("fields.index")
|
||||
->with("success", trans('admin/custom_fields/message.field.delete.success'));
|
||||
return redirect()->route('fields.index',['tab' => array_search($type, Helper::$itemtypes_having_custom_fields)])
|
||||
|
||||
->with('success', trans('admin/custom_fields/message.field.delete.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withErrors(['message' => 'Field does not exist']);
|
||||
@@ -289,7 +306,7 @@ class CustomFieldsController extends Controller
|
||||
$field->fieldset()->sync([]);
|
||||
}
|
||||
|
||||
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.update.success'));
|
||||
return redirect()->route('fields.index',['tab' => $request->get('tab',0)])->with('success', trans('admin/custom_fields/message.field.update.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.field.update.error'));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
@@ -38,7 +39,7 @@ class CustomFieldsetsController extends Controller
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function show($id)
|
||||
public function show( $id)
|
||||
{
|
||||
$cfset = CustomFieldset::with('fields')
|
||||
->where('id', '=', $id)->orderBy('id', 'ASC')->first();
|
||||
@@ -46,7 +47,7 @@ class CustomFieldsetsController extends Controller
|
||||
$this->authorize('view', $cfset);
|
||||
|
||||
if ($cfset) {
|
||||
$custom_fields_list = ['' => 'Add New Field to Fieldset'] + CustomField::pluck('name', 'id')->toArray();
|
||||
$custom_fields_list = ['' => 'Add New Field to Fieldset'] + CustomField::where('type', $cfset->type)->pluck('name', 'id')->toArray();
|
||||
|
||||
$maxid = 0;
|
||||
foreach ($cfset->fields as $field) {
|
||||
@@ -96,6 +97,8 @@ class CustomFieldsetsController extends Controller
|
||||
$fieldset = new CustomFieldset([
|
||||
'name' => $request->get('name'),
|
||||
'user_id' => Auth::user()->id,
|
||||
'type' => Helper::$itemtypes_having_custom_fields[$request->get('tab')]
|
||||
// 'sub' =>
|
||||
]);
|
||||
|
||||
$validator = Validator::make($request->all(), $fieldset->rules);
|
||||
|
||||
@@ -31,7 +31,7 @@ class LabelsController extends Controller
|
||||
|
||||
$exampleAsset->id = 999999;
|
||||
$exampleAsset->name = 'JEN-867-5309';
|
||||
$exampleAsset->asset_tag = '100001';
|
||||
$exampleAsset->asset_tag = 'TCA-00001';
|
||||
$exampleAsset->serial = 'SN9876543210';
|
||||
|
||||
$exampleAsset->company = new Company();
|
||||
|
||||
@@ -76,7 +76,7 @@ class LicenseCheckinController extends Controller
|
||||
|
||||
// Declare the rules for the form validation
|
||||
$rules = [
|
||||
'notes' => 'string|nullable',
|
||||
'note' => 'string|nullable',
|
||||
];
|
||||
|
||||
// Create a new validator instance from our validation rules
|
||||
@@ -97,7 +97,6 @@ class LicenseCheckinController extends Controller
|
||||
// Update the asset data
|
||||
$licenseSeat->assigned_to = null;
|
||||
$licenseSeat->asset_id = null;
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
@@ -129,13 +128,6 @@ class LicenseCheckinController extends Controller
|
||||
$license = License::findOrFail($licenseId);
|
||||
$this->authorize('checkin', $license);
|
||||
|
||||
if (! $license->reassignable) {
|
||||
// Not allowed to checkin
|
||||
Session::flash('error', 'License not reassignable.');
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
|
||||
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
||||
->whereNotNull('assigned_to')
|
||||
->with('user')
|
||||
|
||||
@@ -63,7 +63,6 @@ class LicenseCheckoutController extends Controller
|
||||
|
||||
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
|
||||
$licenseSeat->user_id = Auth::id();
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
|
||||
|
||||
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
||||
|
||||
@@ -137,7 +137,7 @@ class LicenseFilesController extends Controller
|
||||
$this->authorize('view', $license);
|
||||
$this->authorize('licenses.files', $license);
|
||||
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) {
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
@@ -1043,34 +1043,27 @@ class ReportsController extends Controller
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @version v1.0
|
||||
*/
|
||||
public function sentAssetAcceptanceReminder(Request $request)
|
||||
public function sentAssetAcceptanceReminder($acceptanceId = null)
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
if (!$acceptance = CheckoutAcceptance::pending()->find($request->input('acceptance_id'))) {
|
||||
\Log::debug('No pending acceptances');
|
||||
if (!$acceptance = CheckoutAcceptance::pending()->find($acceptanceId)) {
|
||||
// Redirect to the unaccepted assets report page with error
|
||||
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
|
||||
}
|
||||
|
||||
$assetItem = $acceptance->checkoutable;
|
||||
|
||||
\Log::debug(print_r($assetItem, true));
|
||||
|
||||
if (is_null($acceptance->created_at)){
|
||||
\Log::debug('No 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()){
|
||||
\Log::debug('Acceptance date mismatch');
|
||||
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data'));
|
||||
}
|
||||
$logItem = $logItem_res[0];
|
||||
}
|
||||
|
||||
if (!$assetItem->assignedTo->locale){
|
||||
if(!$assetItem->assignedTo->locale){
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$assetItem->assignedTo,
|
||||
new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)
|
||||
|
||||
@@ -136,11 +136,6 @@ class UserFilesController extends Controller
|
||||
*/
|
||||
public function show($userId = null, $fileId = null)
|
||||
{
|
||||
|
||||
if (empty($fileId)) {
|
||||
return redirect()->route('users.show')->with('error', 'Invalid file request');
|
||||
}
|
||||
|
||||
$user = User::find($userId);
|
||||
|
||||
// the license is valid
|
||||
@@ -148,20 +143,18 @@ class UserFilesController extends Controller
|
||||
|
||||
$this->authorize('view', $user);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Display the file inline
|
||||
if (request('inline') == 'true') {
|
||||
$headers = [
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
return Storage::download('private_uploads/users/'.$log->filename, $log->filename, $headers);
|
||||
}
|
||||
|
||||
return Storage::download('private_uploads/users/'.$log->filename);
|
||||
// Display the file inline
|
||||
if (request('inline') == 'true') {
|
||||
$headers = [
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
return Storage::download('private_uploads/users/'.$log->filename, $log->filename, $headers);
|
||||
}
|
||||
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.log_record_not_found'));
|
||||
return Storage::download('private_uploads/users/'.$log->filename);
|
||||
|
||||
}
|
||||
|
||||
// Redirect to the user management page if the user doesn't exist
|
||||
|
||||
@@ -133,6 +133,9 @@ class UsersController extends Controller
|
||||
// we have to invoke the
|
||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
\Log::info("About to call customFill, in the 'store' controller!!!");
|
||||
$user->customFill($request, Auth::user());
|
||||
|
||||
if ($user->save()) {
|
||||
if ($request->filled('groups')) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
@@ -300,6 +303,8 @@ class UsersController extends Controller
|
||||
// Handle uploaded avatar
|
||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
\Log::debug("calling custom fill from the UPDATE method!");
|
||||
$user->customFill($request, Auth::user());
|
||||
//\Log::debug(print_r($user, true));
|
||||
|
||||
// Was the user updated?
|
||||
|
||||
+1
-2
@@ -18,13 +18,12 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\Fideloper\Proxy\TrustProxies::class,
|
||||
\App\Http\Middleware\CheckForSetup::class,
|
||||
\App\Http\Middleware\CheckForDebug::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\SecurityHeaders::class,
|
||||
\App\Http\Middleware\PreventBackHistory::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
|
||||
];
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\DefaultValuesForCustomFields;
|
||||
use Livewire\Component;
|
||||
|
||||
use App\Models\CustomFieldset;
|
||||
@@ -30,7 +32,7 @@ class CustomFieldSetDefaultValuesForModel extends Component
|
||||
$this->fields = CustomFieldset::find($this->fieldset_id)->fields;
|
||||
}
|
||||
|
||||
$this->add_default_values = ($this->model->defaultValues->count() > 0);
|
||||
$this->add_default_values = (DefaultValuesForCustomFields::forPivot($this->model, Asset::class)->count() > 0);
|
||||
}
|
||||
|
||||
public function updatedFieldsetId()
|
||||
|
||||
@@ -100,7 +100,7 @@ class Importer extends Component
|
||||
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) {
|
||||
foreach (CustomField::where('type', \App\Models\Asset::class)->orderBy('name')->get() as $field) { // TODO - generalize?
|
||||
$results[$field->db_column_name()] = $field->name;
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,6 @@ class Importer extends Component
|
||||
'license_email' => trans('admin/licenses/form.to_email'),
|
||||
'license_name' => trans('admin/licenses/form.to_name'),
|
||||
'purchase_order' => trans('admin/licenses/form.purchase_order'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
'reassignable' => trans('admin/licenses/form.reassignable'),
|
||||
'seats' => trans('admin/licenses/form.seats'),
|
||||
'notes' => trans('general.notes'),
|
||||
@@ -485,17 +484,8 @@ class Importer extends Component
|
||||
|
||||
public function selectFile($id)
|
||||
{
|
||||
$this->clearMessage();
|
||||
|
||||
$this->activeFile = Import::find($id);
|
||||
|
||||
if (!$this->activeFile) {
|
||||
$this->message = trans('admin/hardware/message.import.file_missing');
|
||||
$this->message_type = 'danger';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->field_map = null;
|
||||
foreach($this->activeFile->header_row as $element) {
|
||||
if(isset($this->activeFile->field_map[$element])) {
|
||||
@@ -530,12 +520,6 @@ class Importer extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function clearMessage()
|
||||
{
|
||||
$this->message = null;
|
||||
$this->message_type = null;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$this->files = Import::orderBy('id','desc')->get(); //HACK - slows down renders.
|
||||
|
||||
@@ -12,7 +12,7 @@ class SlackSettingsForm extends Component
|
||||
public $webhook_endpoint;
|
||||
public $webhook_channel;
|
||||
public $webhook_botname;
|
||||
public $isDisabled ='disabled' ;
|
||||
public $isDisabled ='' ;
|
||||
public $webhook_name;
|
||||
public $webhook_link;
|
||||
public $webhook_placeholder;
|
||||
@@ -22,17 +22,11 @@ class SlackSettingsForm extends Component
|
||||
|
||||
public Setting $setting;
|
||||
|
||||
public $webhook_endpoint_rules;
|
||||
|
||||
|
||||
protected $rules = [
|
||||
'webhook_endpoint' => 'required_with:webhook_channel|starts_with:http://,https://,ftp://,irc://,https://hooks.slack.com/services/|url|nullable',
|
||||
'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 $messages = [
|
||||
'webhook_endpoint.starts_with' => 'your webhook endpoint should begin with http://, https:// or other protocol.',
|
||||
];
|
||||
|
||||
public function mount() {
|
||||
$this->webhook_text= [
|
||||
@@ -61,7 +55,9 @@ class SlackSettingsForm extends Component
|
||||
$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= '';
|
||||
}
|
||||
@@ -69,8 +65,9 @@ class SlackSettingsForm extends Component
|
||||
}
|
||||
public function updated($field) {
|
||||
|
||||
if($this->webhook_selected != 'general') {
|
||||
$this->validateOnly($field, $this->rules);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedWebhookSelected() {
|
||||
@@ -85,6 +82,7 @@ class SlackSettingsForm extends Component
|
||||
}
|
||||
|
||||
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');
|
||||
@@ -93,6 +91,8 @@ class SlackSettingsForm extends Component
|
||||
$this->isDisabled = 'disabled';
|
||||
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function render()
|
||||
@@ -108,7 +108,6 @@ class SlackSettingsForm extends Component
|
||||
'defaults' => [
|
||||
'exceptions' => false,
|
||||
],
|
||||
'allow_redirects' => false,
|
||||
]);
|
||||
|
||||
$payload = json_encode(
|
||||
@@ -117,23 +116,18 @@ class SlackSettingsForm extends Component
|
||||
'text' => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
|
||||
'username' => e($this->webhook_botname),
|
||||
'icon_emoji' => ':heart:',
|
||||
|
||||
]);
|
||||
|
||||
try {
|
||||
$test = $webhook->post($this->webhook_endpoint, ['body' => $payload]);
|
||||
|
||||
if(($test->getStatusCode() == 302)||($test->getStatusCode() == 301)){
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error_redirect', ['endpoint' => $this->webhook_endpoint]));
|
||||
}
|
||||
$webhook->post($this->webhook_endpoint, ['body' => $payload]);
|
||||
$this->isDisabled='';
|
||||
$this->save_button = trans('general.save');
|
||||
return session()->flash('success' , trans('admin/settings/message.webhook.success', ['webhook_name' => $this->webhook_name]));
|
||||
return session()->flash('success' , 'Your '.$this->webhook_name.' Integration works!');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->isDisabled='disabled';
|
||||
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||
$this->isDisabled= 'disabled';
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
|
||||
}
|
||||
|
||||
@@ -164,7 +158,9 @@ class SlackSettingsForm extends Component
|
||||
if (Helper::isDemoMode()) {
|
||||
session()->flash('error',trans('general.feature_disabled'));
|
||||
} else {
|
||||
$this->validate($this->rules);
|
||||
if ($this->webhook_selected != 'general') {
|
||||
$this->validate($this->rules);
|
||||
}
|
||||
|
||||
$this->setting->webhook_selected = $this->webhook_selected;
|
||||
$this->setting->webhook_endpoint = $this->webhook_endpoint;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
@@ -10,7 +10,7 @@ class TrustProxies extends Middleware
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string|null
|
||||
* @var array<int, string>|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
@@ -19,5 +19,10 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
||||
@@ -34,12 +34,14 @@ class CustomFieldRequest extends FormRequest
|
||||
case 'POST':
|
||||
{
|
||||
$rules['name'] = 'required|unique:custom_fields';
|
||||
$rules['tab'] = 'required';
|
||||
break;
|
||||
}
|
||||
|
||||
// Save all fields
|
||||
case 'PUT':
|
||||
$rules['name'] = 'required';
|
||||
$rules['tab'] = 'required';
|
||||
break;
|
||||
|
||||
// Save only what's passed
|
||||
|
||||
@@ -10,8 +10,6 @@ use App\Models\Supplier;
|
||||
use App\Models\Location;
|
||||
use App\Models\AssetModel;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class ActionlogsTransformer
|
||||
{
|
||||
@@ -45,10 +43,9 @@ class ActionlogsTransformer
|
||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
$icon = $actionlog->present()->icon();
|
||||
$custom_fields = CustomField::all();
|
||||
|
||||
$custom_field = CustomField::all();
|
||||
if ($actionlog->filename!='') {
|
||||
$icon = Helper::filetype_icon($actionlog->filename);
|
||||
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
|
||||
}
|
||||
|
||||
// This is necessary since we can't escape special characters within a JSON object
|
||||
@@ -58,56 +55,17 @@ class ActionlogsTransformer
|
||||
$clean_meta = [];
|
||||
|
||||
if ($meta_array) {
|
||||
|
||||
foreach ($meta_array as $fieldname => $fieldata) {
|
||||
|
||||
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
|
||||
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
|
||||
|
||||
// this is a custom field
|
||||
if (str_starts_with($fieldname, '_snipeit_')) {
|
||||
|
||||
foreach ($custom_fields as $custom_field) {
|
||||
|
||||
if ($custom_field->db_column == $fieldname) {
|
||||
|
||||
if ($custom_field->field_encrypted == '1') {
|
||||
|
||||
// Unset these fields. We need to decrypt them, since even if the decrypted value
|
||||
// didn't change, their value in the DB will, so we have to compare the unencrypted version
|
||||
// to see if the values actually did change
|
||||
unset($clean_meta[$fieldname]);
|
||||
unset($clean_meta[$fieldname]);
|
||||
|
||||
$enc_old = '';
|
||||
$enc_new = '';
|
||||
|
||||
try {
|
||||
$enc_old = \Crypt::decryptString($this->clean_field($fieldata->old));
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Could not decrypt field - maybe the key changed?');
|
||||
}
|
||||
|
||||
try {
|
||||
$enc_new = \Crypt::decryptString($this->clean_field($fieldata->new));
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Could not decrypt field - maybe the key changed?');
|
||||
}
|
||||
|
||||
if ($enc_old != $enc_new) {
|
||||
\Log::debug('custom fields do not match');
|
||||
$clean_meta[$fieldname]['old'] = "************";
|
||||
$clean_meta[$fieldname]['new'] = "************";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( str_starts_with($fieldname, '_snipeit_')){
|
||||
if( $custom_field->where('db_column', '=', $fieldname)->where('field_encrypted', true)){
|
||||
$clean_meta[$fieldname]['old'] = "encrypted";
|
||||
$clean_meta[$fieldname]['new'] = "encrypted";
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
|
||||
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -207,42 +165,24 @@ class ActionlogsTransformer
|
||||
|
||||
|
||||
if(array_key_exists('rtd_location_id',$clean_meta)) {
|
||||
|
||||
$oldRtd = $location->find($clean_meta['rtd_location_id']['old']);
|
||||
$oldRtdName = $oldRtd ? e($oldRtd->name) : trans('general.deleted');
|
||||
|
||||
$newRtd = $location->find($clean_meta['rtd_location_id']['new']);
|
||||
$newRtdName = $newRtd ? e($newRtd->name) : trans('general.deleted');
|
||||
|
||||
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $oldRtdName : '';
|
||||
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $newRtdName : '';
|
||||
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $location->find($clean_meta['rtd_location_id']['old'])->name : trans('general.unassigned');
|
||||
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $location->find($clean_meta['rtd_location_id']['new'])->name : trans('general.unassigned');
|
||||
$clean_meta['Default Location'] = $clean_meta['rtd_location_id'];
|
||||
unset($clean_meta['rtd_location_id']);
|
||||
}
|
||||
|
||||
|
||||
if (array_key_exists('location_id', $clean_meta)) {
|
||||
|
||||
$oldLocation = $location->find($clean_meta['location_id']['old']);
|
||||
$oldLocationName = $oldLocation ? e($oldLocation->name) : trans('general.deleted');
|
||||
|
||||
$newLocation = $location->find($clean_meta['location_id']['new']);
|
||||
$newLocationName = $newLocation ? e($newLocation->name) : trans('general.deleted');
|
||||
|
||||
|
||||
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ". $oldLocationName : '';
|
||||
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ". $newLocationName : '';
|
||||
if(array_key_exists('location_id', $clean_meta)) {
|
||||
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ".$location->find($clean_meta['location_id']['old'])->name : trans('general.unassigned');
|
||||
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ".$location->find($clean_meta['location_id']['new'])->name : trans('general.unassigned');
|
||||
$clean_meta['Current Location'] = $clean_meta['location_id'];
|
||||
unset($clean_meta['location_id']);
|
||||
}
|
||||
|
||||
if(array_key_exists('model_id', $clean_meta)) {
|
||||
|
||||
$oldModel = $model->find($clean_meta['model_id']['old']);
|
||||
$oldModelName = $oldModel ? e($oldModel->name) : trans('admin/models/message.deleted');
|
||||
$oldModelName = $oldModel->name ?? trans('admin/models/message.deleted');
|
||||
|
||||
$newModel = $model->find($clean_meta['model_id']['new']);
|
||||
$newModelName = $newModel ? e($newModel->name) : trans('admin/models/message.deleted');
|
||||
$newModelName = $newModel->name ?? trans('admin/models/message.deleted');
|
||||
|
||||
$clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".$oldModelName;
|
||||
$clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".$newModelName; /** model is required at asset creation */
|
||||
@@ -253,10 +193,10 @@ class ActionlogsTransformer
|
||||
if(array_key_exists('company_id', $clean_meta)) {
|
||||
|
||||
$oldCompany = $company->find($clean_meta['company_id']['old']);
|
||||
$oldCompanyName = $oldCompany ? e($oldCompany->name) : trans('admin/company/message.deleted');
|
||||
$oldCompanyName = $oldCompany->name ?? trans('admin/companies/message.deleted');
|
||||
|
||||
$newCompany = $company->find($clean_meta['company_id']['new']);
|
||||
$newCompanyName = $newCompany ? e($newCompany->name) : trans('admin/company/message.deleted');
|
||||
$newCompanyName = $newCompany->name ?? trans('admin/companies/message.deleted');
|
||||
|
||||
$clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."] ". $oldCompanyName : trans('general.unassigned');
|
||||
$clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ". $newCompanyName : trans('general.unassigned');
|
||||
@@ -266,10 +206,10 @@ class ActionlogsTransformer
|
||||
if(array_key_exists('supplier_id', $clean_meta)) {
|
||||
|
||||
$oldSupplier = $supplier->find($clean_meta['supplier_id']['old']);
|
||||
$oldSupplierName = $oldSupplier ? e($oldSupplier->name) : trans('admin/suppliers/message.deleted');
|
||||
$oldSupplierName = $oldSupplier->name ?? trans('admin/suppliers/message.deleted');
|
||||
|
||||
$newSupplier = $supplier->find($clean_meta['supplier_id']['new']);
|
||||
$newSupplierName = $newSupplier ? e($newSupplier->name) : trans('admin/suppliers/message.deleted');
|
||||
$newSupplierName = $newSupplier->name ?? trans('admin/suppliers/message.deleted');
|
||||
|
||||
$clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ". $oldSupplierName : trans('general.unassigned');
|
||||
$clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ". $newSupplierName : trans('general.unassigned');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\CustomFieldHelper;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
@@ -96,49 +97,7 @@ class AssetsTransformer
|
||||
];
|
||||
|
||||
|
||||
if (($asset->model) && ($asset->model->fieldset) && ($asset->model->fieldset->fields->count() > 0)) {
|
||||
$fields_array = [];
|
||||
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
if ($field->isFieldDecryptable($asset->{$field->db_column})) {
|
||||
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||
$value = (Gate::allows('assets.view.encrypted_custom_fields')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
|
||||
if ($field->format == 'DATE'){
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
} else {
|
||||
$value = strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
}
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
|
||||
} else {
|
||||
$value = $asset->{$field->db_column};
|
||||
|
||||
if (($field->format == 'DATE') && (!is_null($value)) && ($value!='')){
|
||||
$value = Helper::getFormattedDateObject($value, 'date', false);
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->db_column),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
}
|
||||
|
||||
$array['custom_fields'] = $fields_array;
|
||||
}
|
||||
} else {
|
||||
$array['custom_fields'] = new \stdClass; // HACK to force generation of empty object instead of empty list
|
||||
}
|
||||
$array['custom_fields'] = CustomFieldHelper::transform($asset->model->fieldset,$asset);
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'checkout' => ($asset->deleted_at=='' && Gate::allows('checkout', Asset::class)) ? true : false,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CustomFieldset;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
@@ -21,8 +23,13 @@ class CustomFieldsetsTransformer
|
||||
public function transformCustomFieldset(CustomFieldset $fieldset)
|
||||
{
|
||||
$fields = $fieldset->fields;
|
||||
$models = $fieldset->models;
|
||||
$models = [];
|
||||
$modelsArray = [];
|
||||
if ($fieldset->type == Asset::class) {
|
||||
\Log::debug("Item pivot id is: ".$fieldset->item_pivot_id);
|
||||
$models = AssetModel::where('fieldset_id', $fieldset->id)->get();
|
||||
\Log::debug("And the models object count is: ".$models->count());
|
||||
}
|
||||
|
||||
foreach ($models as $model) {
|
||||
$modelsArray[] = [
|
||||
@@ -30,15 +37,21 @@ class CustomFieldsetsTransformer
|
||||
'name' => e($model->name),
|
||||
];
|
||||
}
|
||||
\Log::debug("Models array is: ".print_r($modelsArray,true));
|
||||
|
||||
$array = [
|
||||
'id' => (int) $fieldset->id,
|
||||
'name' => e($fieldset->name),
|
||||
'fields' => (new CustomFieldsTransformer)->transformCustomFields($fields, $fieldset->fields_count),
|
||||
'models' => (new DatatablesTransformer)->transformDatatables($modelsArray, $fieldset->models_count),
|
||||
'customizables' => (new DatatablesTransformer)->transformDatatables($fieldset->customizables(),count($fieldset->customizables())),
|
||||
'created_at' => Helper::getFormattedDateObject($fieldset->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($fieldset->updated_at, 'datetime'),
|
||||
'type' => $fieldset->type,
|
||||
];
|
||||
if ($fieldset->type == Asset::class) {
|
||||
// TODO - removeme - legacy column just for Assets?
|
||||
$array['models'] = (new DatatablesTransformer)->transformDatatables($modelsArray, count($modelsArray));
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ class LicenseSeatsTransformer
|
||||
'name'=> e($seat->location()->name),
|
||||
] : null,
|
||||
'reassignable' => (bool) $seat->license->reassignable,
|
||||
'notes' => e($seat->notes),
|
||||
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
||||
];
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\CustomFieldHelper;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@@ -77,6 +80,8 @@ class UsersTransformer
|
||||
'deleted_at' => ($user->deleted_at) ? Helper::getFormattedDateObject($user->deleted_at, 'datetime') : null,
|
||||
];
|
||||
|
||||
$array['custom_fields'] = CustomFieldHelper::transform(CustomFieldset::where('type',User::class)->first(), $user);
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => (Gate::allows('update', User::class) && ($user->deleted_at == '')),
|
||||
'delete' => (Gate::allows('delete', User::class) && ($user->assets_count == 0) && ($user->licenses_count == 0) && ($user->accessories_count == 0)),
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssetImporter extends ItemImporter
|
||||
{
|
||||
@@ -25,19 +23,20 @@ class AssetImporter extends ItemImporter
|
||||
// ItemImporter handles the general fetching.
|
||||
parent::handle($row);
|
||||
|
||||
// FIXME : YUP!!!!! This shit needs to go (?) Yeah?
|
||||
if ($this->customFields) {
|
||||
foreach ($this->customFields as $customField) {
|
||||
$customFieldValue = $this->array_smart_custom_field_fetch($row, $customField);
|
||||
$customFieldValue = $this->array_smart_custom_field_fetch($row, $customField); // TODO/FIXME - this might require a new 'mode' on customFill()?
|
||||
|
||||
if ($customFieldValue) {
|
||||
if ($customField->field_encrypted == 1) {
|
||||
if ($customField->field_encrypted == 1) { // FIXME - repeated code.
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = \Crypt::encrypt($customFieldValue);
|
||||
$this->log('Custom Field '.$customField->name.': '.\Crypt::encrypt($customFieldValue));
|
||||
} else {
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = $customFieldValue;
|
||||
$this->log('Custom Field '.$customField->name.': '.$customFieldValue);
|
||||
}
|
||||
} else {
|
||||
} else { // FIXME - think this through? Do we want to blank this? Is that how other stuff works?
|
||||
// Clear out previous data.
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = null;
|
||||
}
|
||||
@@ -65,7 +64,6 @@ class AssetImporter extends ItemImporter
|
||||
$asset_tag = Asset::autoincrement_asset();
|
||||
}
|
||||
|
||||
|
||||
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
||||
if ($asset) {
|
||||
if (! $this->updating) {
|
||||
@@ -119,7 +117,12 @@ class AssetImporter extends ItemImporter
|
||||
if (isset($this->item['next_audit_date'])) {
|
||||
$item['next_audit_date'] = $this->item['next_audit_date'];
|
||||
}
|
||||
|
||||
|
||||
$item['asset_eol_date'] = null;
|
||||
if (isset($this->item['asset_eol_date'])) {
|
||||
$item['asset_eol_date'] = $this->item['asset_eol_date'];
|
||||
}
|
||||
|
||||
if ($editingAsset) {
|
||||
$asset->update($item);
|
||||
} else {
|
||||
@@ -132,9 +135,9 @@ class AssetImporter extends ItemImporter
|
||||
$asset->{$custom_field} = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset->save()) {
|
||||
|
||||
|
||||
if ($asset->save()) {
|
||||
$asset->logCreate(trans('general.importer.import_note'));
|
||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ abstract class Importer
|
||||
/**
|
||||
* Default Map of item fields->csv names
|
||||
*
|
||||
* This has been moved into app/Http/Livewire/Importer.php to be more granular.
|
||||
* This has been moved into Livewire/Importer.php to be more granular.
|
||||
* @todo - remove references to this property since we don't use it anymore.
|
||||
*
|
||||
* @var array
|
||||
@@ -120,7 +120,7 @@ abstract class Importer
|
||||
* @author Daniel Meltzer
|
||||
* @since 5.0
|
||||
*/
|
||||
protected function populateCustomFields($headerRow)
|
||||
protected function populateCustomFields($headerRow) // FIXME - what in the actual fuck is this.
|
||||
{
|
||||
// Stolen From https://adamwathan.me/2016/07/14/customizing-keys-when-mapping-collections/
|
||||
// This 'inverts' the fields such that we have a collection of fields indexed by name.
|
||||
|
||||
@@ -10,8 +10,6 @@ use App\Models\Manufacturer;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ItemImporter extends Importer
|
||||
{
|
||||
@@ -90,14 +88,8 @@ class ItemImporter extends Importer
|
||||
}
|
||||
|
||||
$this->item['asset_eol_date'] = null;
|
||||
if($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$csvMatch = $this->findCsvMatch($row, 'asset_eol_date');
|
||||
try {
|
||||
$this->item['asset_eol_date'] = CarbonImmutable::parse($csvMatch)->format('Y-m-d');
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e->getMessage());
|
||||
$this->log('Unable to parse date: '.$csvMatch);
|
||||
}
|
||||
if ($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$this->item['asset_eol_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'asset_eol_date')));
|
||||
}
|
||||
|
||||
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
|
||||
|
||||
@@ -65,7 +65,6 @@ class LicenseImporter extends ItemImporter
|
||||
$this->item['license_name'] = $this->findCsvMatch($row, 'license_name');
|
||||
$this->item['maintained'] = $this->findCsvMatch($row, 'maintained');
|
||||
$this->item['purchase_order'] = $this->findCsvMatch($row, 'purchase_order');
|
||||
$this->item['order_number'] = $this->findCsvMatch($row, 'order_number');
|
||||
$this->item['reassignable'] = $this->findCsvMatch($row, 'reassignable');
|
||||
$this->item['manufacturer'] = $this->createOrFetchManufacturer($this->findCsvMatch($row, 'manufacturer'));
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ use App\Notifications\CheckoutAccessoryNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Exception;
|
||||
use Log;
|
||||
@@ -42,9 +41,14 @@ class CheckoutableListener
|
||||
/**
|
||||
* Make a checkout acceptance and attach it in the notification
|
||||
*/
|
||||
$acceptance = $this->getCheckoutAcceptance($event);
|
||||
$acceptance = $this->getCheckoutAcceptance($event);
|
||||
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event));
|
||||
}
|
||||
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$this->getNotifiables($event),
|
||||
@@ -56,15 +60,8 @@ class CheckoutableListener
|
||||
$this->getCheckoutNotification($event, $acceptance)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckoutNotification($event));
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
Log::error("Exception caught during checkout notification: " . $e->getMessage());
|
||||
Log::error("Exception caught during checkout notification: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,19 +79,22 @@ class CheckoutableListener
|
||||
/**
|
||||
* Send the appropriate notification
|
||||
*/
|
||||
if ($event->checkedOutTo && $event->checkoutable){
|
||||
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
|
||||
->where('assigned_to_id', $event->checkedOutTo->id)
|
||||
->get();
|
||||
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
|
||||
->where('assigned_to_id', $event->checkedOutTo->id)
|
||||
->get();
|
||||
|
||||
foreach($acceptances as $acceptance){
|
||||
if($acceptance->isPending()){
|
||||
$acceptance->delete();
|
||||
}
|
||||
foreach($acceptances as $acceptance){
|
||||
if($acceptance->isPending()){
|
||||
$acceptance->delete();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckinNotification($event));
|
||||
}
|
||||
|
||||
// Use default locale
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
@@ -107,15 +107,8 @@ class CheckoutableListener
|
||||
$this->getCheckinNotification($event)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||
->notify($this->getCheckinNotification($event));
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
Log::error("Exception caught during checkin notification: " . $e->getMessage());
|
||||
Log::error("Exception caught during checkin notification: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,11 +142,9 @@ class CheckoutableListener
|
||||
$notifiables = collect();
|
||||
|
||||
/**
|
||||
* Notify who checked out the item as long as the model can route notifications
|
||||
* Notify the user who checked out the item
|
||||
*/
|
||||
if (method_exists($event->checkedOutTo, 'routeNotificationFor')) {
|
||||
$notifiables->push($event->checkedOutTo);
|
||||
}
|
||||
$notifiables->push($event->checkedOutTo);
|
||||
|
||||
/**
|
||||
* Notify Admin users if the settings is activated
|
||||
|
||||
+17
-41
@@ -9,6 +9,8 @@ use App\Helpers\Helper;
|
||||
use App\Http\Traits\UniqueSerialTrait;
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\Customizable;
|
||||
use App\Models\Traits\HasCustomFields;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use AssetPresenter;
|
||||
@@ -18,6 +20,7 @@ use DB;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
@@ -38,8 +41,19 @@ class Asset extends Depreciable
|
||||
public const ASSET = 'asset';
|
||||
public const USER = 'user';
|
||||
|
||||
use Acceptable;
|
||||
use Acceptable, HasCustomFields;
|
||||
|
||||
public function getFieldsetKey(): object|int|null {
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
public static function getFieldsetUsers(int $fieldset_id): array {
|
||||
$models = [];
|
||||
foreach(AssetModel::where("fieldset_id",$fieldset_id)->get() as $model) {
|
||||
$models[route('models.show', $model->id)] = $model->name.(($model->model_number) ? ' ('.$model->model_number.')' : '');
|
||||
}
|
||||
return $models;
|
||||
}
|
||||
/**
|
||||
* Run after the checkout acceptance was declined by the user
|
||||
*
|
||||
@@ -72,7 +86,6 @@ class Asset extends Depreciable
|
||||
|
||||
protected $casts = [
|
||||
'purchase_date' => 'date',
|
||||
'eol_explicit' => 'boolean',
|
||||
'last_checkout' => 'datetime',
|
||||
'last_checkin' => 'datetime',
|
||||
'expected_checkin' => 'date',
|
||||
@@ -105,8 +118,7 @@ class Asset extends Depreciable
|
||||
'serial' => 'unique_serial|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'supplier_id' => 'exists:suppliers,id|nullable',
|
||||
'asset_eol_date' => 'date|nullable',
|
||||
'eol_explicit' => 'boolean|nullable',
|
||||
'asset_eol_date' => 'date|max:10|min:10|nullable',
|
||||
'byod' => 'boolean',
|
||||
];
|
||||
|
||||
@@ -138,10 +150,8 @@ class Asset extends Depreciable
|
||||
'expected_checkin',
|
||||
'byod',
|
||||
'asset_eol_date',
|
||||
'eol_explicit',
|
||||
'last_audit_date',
|
||||
'next_audit_date',
|
||||
'asset_eol_date',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
@@ -192,40 +202,6 @@ class Asset extends Depreciable
|
||||
$this->attributes['expected_checkin'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles the custom field validation for assets
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function save(array $params = [])
|
||||
{
|
||||
if ($this->model_id != '') {
|
||||
$model = AssetModel::find($this->model_id);
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
|
||||
foreach ($model->fieldset->fields as $field){
|
||||
if($field->format == 'BOOLEAN'){
|
||||
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
$this->rules += $model->fieldset->validation_rules();
|
||||
|
||||
foreach ($this->model->fieldset->fields as $field){
|
||||
if($field->format == 'BOOLEAN'){
|
||||
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return parent::save($params);
|
||||
}
|
||||
|
||||
|
||||
public function getDisplayNameAttribute()
|
||||
{
|
||||
return $this->present()->name();
|
||||
@@ -1527,7 +1503,7 @@ class Asset extends Depreciable
|
||||
*
|
||||
* In short, this set of statements tells the query builder to ONLY query against an
|
||||
* actual field that's being passed if it doesn't meet known relational fields. This
|
||||
* allows us to query custom fields directly in the assetsv table
|
||||
* allows us to query custom fields directly in the assets table
|
||||
* (regardless of their name) and *skip* any fields that we already know can only be
|
||||
* searched through relational searches that we do earlier in this method.
|
||||
*
|
||||
|
||||
@@ -150,6 +150,7 @@ class AssetModel extends SnipeModel
|
||||
*/
|
||||
public function fieldset()
|
||||
{
|
||||
// this is actually OK - we don't *need* to do this, but it's okay to make references from Model to fieldset
|
||||
return $this->belongsTo(\App\Models\CustomFieldset::class, 'fieldset_id');
|
||||
}
|
||||
|
||||
@@ -158,18 +159,6 @@ class AssetModel extends SnipeModel
|
||||
return $this->fieldset()->first()->fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the model -> custom field default values relationship
|
||||
*
|
||||
* @author hannah tinkler
|
||||
* @since [v4.3]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function defaultValues()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\CustomField::class, 'models_custom_fields')->withPivot('default_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full url for the image
|
||||
*
|
||||
@@ -291,9 +280,4 @@ class AssetModel extends SnipeModel
|
||||
{
|
||||
return $query->leftJoin('categories', 'models.category_id', '=', 'categories.id')->orderBy('categories.name', $order);
|
||||
}
|
||||
|
||||
public function scopeOrderFieldset($query, $order)
|
||||
{
|
||||
return $query->leftJoin('custom_fieldsets', 'models.fieldset_id', '=', 'custom_fieldsets.id')->orderBy('custom_fieldsets.name', $order);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-42
@@ -16,7 +16,7 @@ class CustomField extends Model
|
||||
UniqueUndeletedTrait;
|
||||
|
||||
/**
|
||||
* Custom field predfined formats
|
||||
* Custom field predefined formats
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@@ -53,6 +53,7 @@ class CustomField extends Model
|
||||
'field_encrypted' => 'nullable|boolean',
|
||||
'auto_add_to_fieldsets' => 'boolean',
|
||||
'show_in_listview' => 'boolean',
|
||||
'type' => 'required'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -75,30 +76,19 @@ class CustomField extends Model
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* This is confusing, since it's actually the custom fields table that
|
||||
* we're usually modifying, but since we alter the assets table, we have to
|
||||
* say that here, otherwise the new fields get added onto the custom fields
|
||||
* table instead of the assets table.
|
||||
*
|
||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public static $table_name = 'assets';
|
||||
|
||||
/**
|
||||
* Convert the custom field's name property to a db-safe string.
|
||||
*
|
||||
* We could probably have used str_slug() here but not sure what it would
|
||||
* do with previously existing values. - @snipe
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.4]
|
||||
* @return string
|
||||
* @since [v3.4]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public static function name_to_db_name($name)
|
||||
{
|
||||
return '_snipeit_'.preg_replace('/[^a-zA-Z0-9]/', '_', strtolower($name));
|
||||
return '_snipeit_' . preg_replace('/[^a-zA-Z0-9]/', '_', strtolower($name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,23 +99,22 @@ class CustomField extends Model
|
||||
* if they have changed, so we handle that here so that we don't have to remember
|
||||
* to do it in the controllers.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.4]
|
||||
* @return bool
|
||||
* @since [v3.4]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
self::created(function ($custom_field) {
|
||||
|
||||
// Column already exists on the assets table - nothing to do here.
|
||||
// This *shouldn't* happen in the wild.
|
||||
if (Schema::hasColumn(self::$table_name, $custom_field->db_column)) {
|
||||
if (Schema::hasColumn($custom_field->getTableName(), $custom_field->db_column)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the column name in the assets table
|
||||
Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
||||
Schema::table($custom_field->getTableName(), function ($table) use ($custom_field) {
|
||||
$table->text($custom_field->convertUnicodeDbSlug())->nullable();
|
||||
});
|
||||
|
||||
@@ -138,7 +127,7 @@ class CustomField extends Model
|
||||
|
||||
// Column already exists on the assets table - nothing to do here.
|
||||
if ($custom_field->isDirty('name')) {
|
||||
if (Schema::hasColumn(self::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
||||
if (Schema::hasColumn($custom_field->getTableName(), $custom_field->convertUnicodeDbSlug())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -148,7 +137,7 @@ class CustomField extends Model
|
||||
$platform->registerDoctrineTypeMapping('enum', 'string');
|
||||
|
||||
// Rename the field if the name has changed
|
||||
Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
||||
Schema::table($custom_field->getTableName(), function ($table) use ($custom_field) {
|
||||
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal('name')), $custom_field->convertUnicodeDbSlug());
|
||||
});
|
||||
|
||||
@@ -164,12 +153,19 @@ class CustomField extends Model
|
||||
|
||||
// Drop the assets column if we've deleted it from custom fields
|
||||
self::deleting(function ($custom_field) {
|
||||
return Schema::table(self::$table_name, function ($table) use ($custom_field) {
|
||||
return Schema::table($custom_field->getTableName(), function ($table) use ($custom_field) {
|
||||
$table->dropColumn($custom_field->db_column);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function getTableName()
|
||||
{
|
||||
$type = $this->type;
|
||||
$instance = new $type();
|
||||
return $instance->getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the customfield -> fieldset relationship
|
||||
*
|
||||
@@ -200,31 +196,23 @@ class CustomField extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the customfield -> default values relationship
|
||||
*
|
||||
* @author Hannah Tinkler
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function defaultValues()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\AssetModel::class, 'models_custom_fields')->withPivot('default_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value for a given model using the defaultValues
|
||||
* Returns the default value for a given 'item' using the defaultValues
|
||||
* relationship
|
||||
*
|
||||
* @param int $modelId
|
||||
* @return string
|
||||
*/
|
||||
public function defaultValue($modelId)
|
||||
public function defaultValue($pivot_id)
|
||||
{
|
||||
return $this->defaultValues->filter(function ($item) use ($modelId) {
|
||||
return $item->pivot->asset_model_id == $modelId;
|
||||
})->map(function ($item) {
|
||||
return $item->pivot->default_value;
|
||||
})->first();
|
||||
/*
|
||||
below, you might think you need to add:
|
||||
|
||||
where('type', $this->type),
|
||||
|
||||
but the type can be inferred from by the custom_field itself (which also has a type)
|
||||
can't use forPivot() here because we don't have an object yet. (TODO?)
|
||||
*/
|
||||
DefaultValuesForCustomFields::where('item_pivot_id', $pivot_id)->where('custom_field_id',$this->id)->first()?->default_value; //TODO - php8-only operator!
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ class CustomFieldset extends Model
|
||||
*/
|
||||
public $rules = [
|
||||
'name' => 'required|unique:custom_fieldsets',
|
||||
''
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -48,11 +49,13 @@ class CustomFieldset extends Model
|
||||
*
|
||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function models()
|
||||
public function customizables() // TODO - I don't like this name, but I can't think of anything better
|
||||
{
|
||||
return $this->hasMany(\App\Models\AssetModel::class, 'fieldset_id');
|
||||
$customizable_class_name = $this->type; //TODO - copypasta from Customizable trait?
|
||||
\Log::debug("Customizable Class name is: ".$customizable_class_name);
|
||||
return $customizable_class_name::getFieldsetUsers($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +80,7 @@ class CustomFieldset extends Model
|
||||
*/
|
||||
public function validation_rules()
|
||||
{
|
||||
\Log::debug("CALLING validation_rules FOR customfiledsets!");
|
||||
$rules = [];
|
||||
foreach ($this->fields as $field) {
|
||||
$rule = [];
|
||||
@@ -90,7 +94,12 @@ class CustomFieldset extends Model
|
||||
$rule[] = 'unique_undeleted';
|
||||
}
|
||||
|
||||
array_push($rule, $field->attributes['format']);
|
||||
\Log::debug("Field Format for".$field->name." is: ".$field->format);
|
||||
if($field->format == 'DATE') { //we do a weird mutator thing, it's confusing - but, yes, it's all-caps
|
||||
$rule[] = 'date_format:Y-m-d';
|
||||
} else {
|
||||
array_push($rule, $field->attributes['format']);
|
||||
}
|
||||
$rules[$field->db_column_name()] = $rule;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class DefaultValuesForCustomFields extends Model
|
||||
{
|
||||
use HasFactory, ValidatingTrait;
|
||||
|
||||
protected $rules = [
|
||||
'type' => 'required'
|
||||
];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public function field() {
|
||||
return $this->belongsTo('custom_fields');
|
||||
}
|
||||
|
||||
// There is, effectively, another 'relation' here, but it's weirdly polymorphic
|
||||
// and impossible to represent in Laravel.
|
||||
// we have a 'type', and we have an 'item_pivot_id' -
|
||||
// For example, in Assets the 'type' would be App\Models\Asset, and the 'item_pivot_id' would be a model_id
|
||||
// I can't come up with any way to represent this in Laravel/Eloquent
|
||||
|
||||
// TODO: might be getting overly-fancy here; maybe just want to do an ID? Instead of an Eloquent Model?
|
||||
public function scopeForPivot(Builder $query, Model $item, string $class) {
|
||||
return $query->where('item_pivot_id', $item->id)->where('type', $class);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class Department extends SnipeModel
|
||||
{
|
||||
use CompanyableTrait;
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,6 @@ class Field {
|
||||
|
||||
public static function makeArray(Field $field, Asset $asset) {
|
||||
return $field->getOptions()
|
||||
// filter out any FieldOptions that are accidentally null
|
||||
->filter()
|
||||
->map(fn($option) => $option->toArray($asset))
|
||||
->filter(fn($result) => $result['value'] != null);
|
||||
}
|
||||
@@ -38,4 +36,4 @@ class Field {
|
||||
->map(fn($optionString) => FieldOption::fromString($optionString));
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use TCPDF;
|
||||
use TCPDF_STATIC;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
* Model for Labels.
|
||||
@@ -373,8 +372,8 @@ abstract class Label
|
||||
if (empty($value)) return;
|
||||
try {
|
||||
$pdf->write1DBarcode($value, $type, $x, $y, $width, $height, null, ['stretch'=>true]);
|
||||
} catch (\Exception|TypeError $e) {
|
||||
\Log::debug('The 1D barcode ' . $value . ' is not compliant with the barcode type '. $type);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('The 1D barcode ' . $value . ' is not compliant with the barcode type '. $type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -252,10 +252,13 @@ class Ldap extends Model
|
||||
$user->last_name = $item['lastname'];
|
||||
$user->username = $item['username'];
|
||||
$user->email = $item['email'];
|
||||
$user->password = $user->noPassword();
|
||||
|
||||
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
||||
|
||||
$user->password = bcrypt($password);
|
||||
} else {
|
||||
$pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 25);
|
||||
$user->password = bcrypt($pass);
|
||||
}
|
||||
|
||||
$user->activated = 1;
|
||||
@@ -265,7 +268,7 @@ class Ldap extends Model
|
||||
if ($user->save()) {
|
||||
return $user;
|
||||
} else {
|
||||
\Log::debug('Could not create user.'.$user->getErrors());
|
||||
LOG::debug('Could not create user.'.$user->getErrors());
|
||||
throw new Exception('Could not create user: '.$user->getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ class SCIMUser extends User
|
||||
protected $throwValidationExceptions = true; // we want model-level validation to fully THROW, not just return false
|
||||
|
||||
public function __construct(array $attributes = []) {
|
||||
$attributes['password'] = $this->noPassword();
|
||||
$attributes['password'] = "*NO PASSWORD*";
|
||||
// $attributes['activated'] = 1;
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use App\Models\DefaultValuesForCustomFields;
|
||||
|
||||
/*********************************
|
||||
* Trait HasCustomFields
|
||||
* @package App\Models\Traits
|
||||
*
|
||||
* How to use: declare a PHP function getFieldset that will return your fieldset (not the ID, the actual set)
|
||||
*
|
||||
*/
|
||||
|
||||
trait HasCustomFields
|
||||
{
|
||||
protected static function bootHasCustomFields()
|
||||
{
|
||||
// https://tech.chrishardie.com/2022/define-fire-listen-custom-laravel-model-events-trait/
|
||||
|
||||
static::registerModelEvent('validating', function ($model, $event) {
|
||||
\Log::debug("Uh, something happened? Something good, maybe?");
|
||||
\Log::debug("model: $model, event: $event");
|
||||
self::augmentValidationRulesForCustomFields($model);
|
||||
});
|
||||
}
|
||||
|
||||
/***************
|
||||
* @return CustomFieldset|null
|
||||
*
|
||||
* This function by default will use the "getFieldsetKey()" method to
|
||||
* return the customFieldset (or null) for this particular item. If
|
||||
* necessary, you can override this method if your getFieldsetKey()
|
||||
* cannot respond to `->fieldset` or `->id`.
|
||||
*/
|
||||
public function getFieldset(): ?CustomFieldset {
|
||||
$pivot = $this->getFieldsetKey();
|
||||
if(is_int($pivot)) { //why does this look just like the other thing? (below, look for is_int()
|
||||
return CustomFieldset::find($pivot);
|
||||
}
|
||||
return $pivot->fieldset;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* @return Object|int|null
|
||||
* (if this is in PHP 8.0, can we just put that as the signature?)
|
||||
*
|
||||
* This is the main method you have to override. It should either return an
|
||||
* Object who you can call `->fieldset` on and get a fieldset object, and also
|
||||
* be able to call `->id` on to get a unique key to be able to show custom fields.
|
||||
* For example, for Assets, the element that is returned is the 'model' for the Asset.
|
||||
* For something like Users, which will probably have only one universal set of custom fields,
|
||||
* it should just return the Fieldset ID for it. Or, if there are no custom fields, it should
|
||||
* return null
|
||||
*/
|
||||
abstract public function getFieldsetKey(): Object|int|null; // php v8 minimum, GOOD. TODO
|
||||
|
||||
/***********************
|
||||
* @param int $fieldset_id
|
||||
* @return Collection
|
||||
*
|
||||
* This is the main method you need to override to return a list of things that are *using* this fieldset
|
||||
* The format is an array with keys: a URL, and values. So, for assets, it might return
|
||||
* {
|
||||
* "models/14" => "MacBook Pro 13 (model no: 12345)"
|
||||
* }
|
||||
*/
|
||||
abstract public static function getFieldsetUsers(int $fieldset_id): array;
|
||||
|
||||
public static function augmentValidationRulesForCustomFields($model) {
|
||||
\Log::debug("Augmenting validation rules for custom fields!!!!!!");
|
||||
$fieldset = $model->getFieldset();
|
||||
if ($fieldset) {
|
||||
foreach ($fieldset->fields as $field){
|
||||
if($field->format == 'BOOLEAN'){ // TODO - this 'feels' like entanglement of concerns?
|
||||
$model->{$field->db_column} = filter_var($model->{$model->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$model->rules) {
|
||||
$model->rules = [];
|
||||
}
|
||||
$model->rules += $model->getFieldset()->validation_rules();
|
||||
\Log::debug("FINAL RULES ARE: ".print_r($model->rules,true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getDefaultValue(CustomField $field)
|
||||
{
|
||||
$pivot = $this->getFieldsetKey(); // TODO - feels copypasta-ish?
|
||||
$key_id = null;
|
||||
|
||||
if( is_int($pivot) ) { // TODO: *WHY* does this code repeat?!
|
||||
$key_id = $pivot; // now we're done
|
||||
} elseif( is_object($pivot) ) {
|
||||
$key_id = $pivot?->id;
|
||||
}
|
||||
if(is_null($key_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO - begninng to think my custom scope really should be just an integer :/
|
||||
return DefaultValuesForCustomFields::where('type',self::class)
|
||||
->where('custom_field_id',$field->id)
|
||||
->where('item_pivot_id',$key_id)->first()?->default_value;
|
||||
}
|
||||
|
||||
public function customFill(Request $request, User $user, bool $shouldSetDefaults = false) {
|
||||
if ($this->getFieldset()) {
|
||||
foreach ($this->getFieldset()->fields as $field) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$field_value = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$field_value = $request->input($field->db_column);
|
||||
}
|
||||
|
||||
if ($shouldSetDefaults && (is_null($field_value) || $field_value === '')) {
|
||||
$field_value = $this->getDefaultValue($field);
|
||||
}
|
||||
if ($field->field_encrypted == '1') {
|
||||
if ($user->can('admin')) {
|
||||
$this->{$field->db_column} = \Crypt::encrypt($field_value);
|
||||
}
|
||||
} else {
|
||||
$this->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-16
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\HasCustomFields;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use DB;
|
||||
@@ -31,6 +32,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
use Notifiable;
|
||||
use Presentable;
|
||||
use Searchable;
|
||||
use HasCustomFields;
|
||||
|
||||
protected $hidden = ['password', 'remember_token', 'permissions', 'reset_password_code', 'persist_code'];
|
||||
protected $table = 'users';
|
||||
@@ -134,6 +136,20 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'manager' => ['first_name', 'last_name', 'username'],
|
||||
];
|
||||
|
||||
public function getFieldsetKey(): object|int|null
|
||||
{
|
||||
// TODO/FIXME - that's hardcoded text, but what language should you use?! I don't know.
|
||||
// also TODO - is this going to beat on the DB too hard?
|
||||
return CustomFieldset::where('type', User::class)->first()?->id;
|
||||
}
|
||||
|
||||
public static function getFieldsetUsers(int $fieldset_id): array
|
||||
{
|
||||
return [
|
||||
'no_idea_what_id_to_put' => 'No idea what string to put?' // FIXME obvs.
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally check the user permission for the given section
|
||||
*
|
||||
@@ -456,22 +472,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return $this->belongsToMany(Asset::class, 'checkout_requests', 'user_id', 'requestable_id')->whereNull('canceled_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a common string when the user has been imported/synced from:
|
||||
*
|
||||
* - LDAP without password syncing
|
||||
* - SCIM
|
||||
* - CSV import where no password was provided
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.2.0]
|
||||
* @return string
|
||||
*/
|
||||
public function noPassword()
|
||||
{
|
||||
return "*** NO PASSWORD ***";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope to return NOT-deleted users
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssetObserver
|
||||
{
|
||||
@@ -120,42 +119,4 @@ class AssetObserver
|
||||
$logAction->user_id = Auth::id();
|
||||
$logAction->logaction('delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes every time an asset is saved.
|
||||
*
|
||||
* This matters specifically because any database fields affected here MUST already exist on
|
||||
* the assets table (and/or any related models), or related migrations WILL fail.
|
||||
*
|
||||
* For example, if there is a database migration that's a bit older and modifies an asset, if the save
|
||||
* fires before a field gets created in a later migration and that field in the later migration
|
||||
* is used in this observer, it doesn't actually exist yet and the migration will break unless we
|
||||
* use saveQuietly() in the migration which skips this observer.
|
||||
*
|
||||
* @see https://github.com/snipe/snipe-it/issues/13723#issuecomment-1761315938
|
||||
*/
|
||||
public function saving(Asset $asset)
|
||||
{
|
||||
// determine if calculated eol and then calculate it - this should only happen on a new asset
|
||||
if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && !is_null($asset->model->eol)){
|
||||
$asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
|
||||
// determine if explicit and set eol_explicit to true
|
||||
if (!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) {
|
||||
if($asset->model->eol) {
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if($months != $asset->model->eol) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
}
|
||||
} elseif (!is_null($asset->asset_eol_date) && is_null($asset->purchase_date)) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model->eol))) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Presenters;
|
||||
|
||||
use App\Helpers\CustomFieldHelper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use Carbon\CarbonImmutable;
|
||||
use App\Models\CustomFieldset;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
@@ -143,8 +145,8 @@ class AssetPresenter extends Presenter
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'age',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.age'),
|
||||
], [
|
||||
@@ -283,25 +285,21 @@ class AssetPresenter extends Presenter
|
||||
// models. We only pass the fieldsets that pertain to each asset (via their model) so that we
|
||||
// don't junk up the REST API with tons of custom fields that don't apply
|
||||
|
||||
$fields = CustomField::whereHas('fieldset', function ($query) {
|
||||
$query->whereHas('models');
|
||||
})->get();
|
||||
//only get fieldsets that have fields
|
||||
$fieldsets = CustomFieldset::where("type", Asset::class)->whereHas('fields')->get();
|
||||
$ids = [];
|
||||
foreach($fieldsets as $fieldset) {
|
||||
if (count($fieldset->customizables()) > 0) { //only get fieldsets that are 'in use'
|
||||
$ids[] = $fieldset->id;
|
||||
}
|
||||
}
|
||||
|
||||
$fields = CustomField::whereIn('id',$ids)->get(); // FIXME: d'oh! this is wrong. We just got fieldsets, above. Now we're getting fields?
|
||||
// Note: We do not need to e() escape the field names here, as they are already escaped when
|
||||
// they are presented in the blade view. If we escape them here, custom fields with quotes in their
|
||||
// name can break the listings page. - snipe
|
||||
foreach ($fields as $field) {
|
||||
$layout[] = [
|
||||
'field' => 'custom_fields.'.$field->db_column,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => $field->name,
|
||||
'formatter'=> 'customFieldsFormatter',
|
||||
'escape' => true,
|
||||
'class' => ($field->field_encrypted == '1') ? 'css-padlock' : '',
|
||||
'visible' => ($field->show_in_listview == '1') ? true : false,
|
||||
];
|
||||
$layout[] = CustomFieldHelper::present($field);
|
||||
}
|
||||
|
||||
$layout[] = [
|
||||
@@ -430,7 +428,10 @@ class AssetPresenter extends Presenter
|
||||
public function eol_date()
|
||||
{
|
||||
if (($this->purchase_date) && ($this->model->model) && ($this->model->model->eol)) {
|
||||
return CarbonImmutable::parse($this->purchase_date)->addMonths($this->model->model->eol)->format('Y-m-d');
|
||||
$date = date_create($this->purchase_date);
|
||||
date_add($date, date_interval_create_from_date_string($this->model->model->eol.' months'));
|
||||
|
||||
return date_format($date, 'Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -254,14 +254,6 @@ class LicensePresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'locationsLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'notes',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'visible' => false,
|
||||
'title' => trans('general.notes'),
|
||||
'formatter' => 'notesFormatter'
|
||||
],
|
||||
[
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -2,8 +2,14 @@
|
||||
|
||||
namespace App\Presenters;
|
||||
|
||||
use App\Helpers\CustomFieldHelper;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@@ -359,6 +365,30 @@ class UserPresenter extends Presenter
|
||||
],
|
||||
];
|
||||
|
||||
// TODO - FIXME - this is all copy-pasta'ed from the AssetPresenter! <start>
|
||||
//only get fieldsets that have fields
|
||||
$fieldsets = CustomFieldset::where("type", User::class)->whereHas('fields')->get();
|
||||
$ids = [];
|
||||
foreach($fieldsets as $fieldset) {
|
||||
if (count($fieldset->customizables()) > 0) { //only get fieldsets that are 'in use'
|
||||
\Log::debug("Found a fieldset! It's: ".$fieldset->id);
|
||||
$ids[] = $fieldset->id;
|
||||
} else {
|
||||
\Log::debug("Didn't find fieldset: ".$fieldset->id);
|
||||
}
|
||||
}
|
||||
|
||||
$fields = CustomField::whereHas('fieldset', function (Builder $query) use($ids) {
|
||||
$query->whereIn('custom_fieldsets.id', $ids);
|
||||
})->get();
|
||||
// Note: We do not need to e() escape the field names here, as they are already escaped when
|
||||
// they are presented in the blade view. If we escape them here, custom fields with quotes in their
|
||||
// name can break the listings page. - snipe
|
||||
foreach ($fields as $field) {
|
||||
\Log::debug("iterating through fields!");
|
||||
$layout[] = CustomFieldHelper::present($field);
|
||||
}
|
||||
|
||||
return json_encode($layout);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
]);
|
||||
|
||||
$this->registerPolicies();
|
||||
Passport::routes();
|
||||
//Passport::routes(); //this is no longer required in newer passport versions
|
||||
Passport::tokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||
Passport::refreshTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||
Passport::personalAccessTokensExpireIn(Carbon::now()->addYears(config('passport.expiration_years')));
|
||||
|
||||
@@ -33,33 +33,18 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
// Make sure the limit is actually set, is an integer and does not exceed system limits
|
||||
\App::singleton('api_limit_value', function () {
|
||||
$limit = config('app.max_results');
|
||||
$int_limit = intval(request('limit'));
|
||||
|
||||
if ((abs($int_limit) > 0) && ($int_limit <= config('app.max_results'))) {
|
||||
$limit = abs($int_limit);
|
||||
if ((abs(intval(request('limit'))) > 0) && (abs(request('limit')) <= config('app.max_results'))) {
|
||||
$limit = abs(request('limit'));
|
||||
}
|
||||
|
||||
// \Log::debug('Max in env: '.config('app.max_results'));
|
||||
// \Log::debug('Original requested limit: '.request('limit'));
|
||||
// \Log::debug('Int limit: '.$int_limit);
|
||||
// \Log::debug('Modified limit: '.$limit);
|
||||
// \Log::debug('------------------------------');
|
||||
|
||||
\Log::debug('Max in env: '.config('app.max_results'));
|
||||
\Log::debug('Original requested limit: '.request('limit'));
|
||||
\Log::debug('Modified limit: '.$limit);
|
||||
\Log::debug('------------------------------');
|
||||
|
||||
return $limit;
|
||||
});
|
||||
|
||||
// Make sure the offset is actually set and is an integer
|
||||
\App::singleton('api_offset_value', function () {
|
||||
$offset = intval(request('offset'));
|
||||
// \Log::debug('Original requested offset: '.request('offset'));
|
||||
// \Log::debug('Modified offset: '.$offset);
|
||||
// \Log::debug('------------------------------');
|
||||
|
||||
|
||||
return $offset;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Set some common variables so that they're globally available.
|
||||
|
||||
+13
-26
@@ -10,14 +10,8 @@
|
||||
],
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"type": "project",
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/grokability/laravel-scim-server"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.3 <8.2",
|
||||
"php": "8.0 - 8.2",
|
||||
"ext-curl": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-json": "*",
|
||||
@@ -29,56 +23,49 @@
|
||||
"barryvdh/laravel-debugbar": "^3.6",
|
||||
"barryvdh/laravel-dompdf": "^2.0",
|
||||
"doctrine/cache": "^1.10",
|
||||
"doctrine/common": "^2.12",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"doctrine/inflector": "^1.3",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"eduardokum/laravel-mail-auto-embed": "^1.0",
|
||||
"eduardokum/laravel-mail-auto-embed": "^2.0",
|
||||
"enshrined/svg-sanitize": "^0.15.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"facade/ignition": "^2.10",
|
||||
"fideloper/proxy": "^4.3",
|
||||
"fruitcake/laravel-cors": "^2.2",
|
||||
"spatie/laravel-ignition": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"intervention/image": "^2.5",
|
||||
"javiereguiluz/easyslugger": "^1.0",
|
||||
"laravel/framework": "^8.46",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/helpers": "^1.4",
|
||||
"laravel/passport": "^10.1",
|
||||
"laravel/passport": "^11.0",
|
||||
"laravel/slack-notification-channel": "^2.3",
|
||||
"laravel/socialite": "^5.6",
|
||||
"laravel/tinker": "^2.6",
|
||||
"laravel/ui": "^3.3",
|
||||
"laravel/ui": "^4.0",
|
||||
"laravelcollective/html": "^6.2",
|
||||
"lcobucci/clock": "^1.2.0|^2.0.0",
|
||||
"lcobucci/jwt": "^3.4.5|^4.0.4",
|
||||
"league/csv": "^9.7",
|
||||
"league/flysystem-aws-s3-v3": "^1.0",
|
||||
"league/flysystem-cached-adapter": "^1.1",
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"livewire/livewire": "^2.4",
|
||||
"mediconesystems/livewire-datatables": "^0.5.0",
|
||||
"neitanod/forceutf8": "^2.0",
|
||||
"nesbot/carbon": "^2.32",
|
||||
"nunomaduro/collision": "^5.4",
|
||||
"nunomaduro/collision": "^6.1",
|
||||
"onelogin/php-saml": "^3.4",
|
||||
"paragonie/constant_time_encoding": "^2.3",
|
||||
"paragonie/sodium_compat": "^1.19",
|
||||
"phpdocumentor/reflection-docblock": "^5.1",
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"pragmarx/google2fa-laravel": "^1.3",
|
||||
"rollbar/rollbar-laravel": "^7.0",
|
||||
"spatie/laravel-backup": "^6.16",
|
||||
"symfony/polyfill-mbstring": "^1.22",
|
||||
"rollbar/rollbar-laravel": "^8.0",
|
||||
"spatie/laravel-backup": "^8.0",
|
||||
"tecnickcom/tc-lib-barcode": "^1.15",
|
||||
"tecnickcom/tcpdf": "^6.5",
|
||||
"unicodeveloper/laravel-password": "^1.0",
|
||||
"watson/validating": "^6.1"
|
||||
"watson/validating": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^6.6",
|
||||
"brianium/paratest": "^v6.4.4",
|
||||
"fakerphp/faker": "^1.16",
|
||||
"mockery/mockery": "^1.4",
|
||||
"nunomaduro/larastan": "^1.0",
|
||||
"nunomaduro/larastan": "^2.0",
|
||||
"nunomaduro/phpinsights": "^2.7",
|
||||
"phpunit/php-token-stream": "^3.1",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
|
||||
Generated
+3035
-3931
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -239,7 +239,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'min_php' => '7.4.0',
|
||||
'min_php' => '7.2.5',
|
||||
|
||||
|
||||
/*
|
||||
@@ -289,7 +289,6 @@ return [
|
||||
Intervention\Image\ImageServiceProvider::class,
|
||||
Collective\Html\HtmlServiceProvider::class,
|
||||
Spatie\Backup\BackupServiceProvider::class,
|
||||
Fideloper\Proxy\TrustedProxyServiceProvider::class,
|
||||
PragmaRX\Google2FALaravel\ServiceProvider::class,
|
||||
Laravel\Passport\PassportServiceProvider::class,
|
||||
Laravel\Tinker\TinkerServiceProvider::class,
|
||||
|
||||
@@ -35,13 +35,6 @@ return [
|
||||
|
||||
'files' => [
|
||||
|
||||
/*
|
||||
* This path is used to make directories in resulting zip-file relative
|
||||
* Set to false to include complete absolute path
|
||||
* Example: base_path()
|
||||
*/
|
||||
'relative_path' => base_path(),
|
||||
|
||||
/*
|
||||
* The list of directories and files that will be included in the backup.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DO NOT EDIT THIS FILE DIRECTLY.
|
||||
@@ -57,6 +59,12 @@ return [
|
||||
*
|
||||
* @link https://symfony.com/doc/current/deployment/proxies.html
|
||||
*/
|
||||
'headers' => Illuminate\Http\Request::HEADER_X_FORWARDED_ALL,
|
||||
'headers' => Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB,
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v6.2.3',
|
||||
'full_app_version' => 'v6.2.3 - build 11759-g8c4bf74f9',
|
||||
'build_version' => '11759',
|
||||
'app_version' => 'v6.2.0-pre',
|
||||
'full_app_version' => 'v6.2.0-pre - build 11391-g319cb2305',
|
||||
'build_version' => '11391',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'g8c4bf74f9',
|
||||
'full_hash' => 'v6.2.3-42-g8c4bf74f9',
|
||||
'branch' => 'master',
|
||||
'hash_version' => 'g319cb2305',
|
||||
'full_hash' => 'v6.2.0-pre-451-g319cb2305',
|
||||
'branch' => 'develop',
|
||||
);
|
||||
@@ -8,8 +8,6 @@ use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class AssetFactory extends Factory
|
||||
@@ -50,18 +48,6 @@ class AssetFactory extends Factory
|
||||
'last_checkout' => null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function configure()
|
||||
{
|
||||
return $this->afterMaking(function (Asset $asset) {
|
||||
// calculates the EOL date most of the time, but sometimes sets a random date so we have some explicits
|
||||
// the explicit boolean gets set in the saving() method on the observer
|
||||
$asset->asset_eol_date = $this->faker->boolean(5)
|
||||
? CarbonImmutable::parse($asset->purchase_date)->addMonths(rand(0, 20))->format('Y-m-d')
|
||||
: CarbonImmutable::parse($asset->purchase_date)->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
});
|
||||
}
|
||||
|
||||
public function laptopMbp()
|
||||
{
|
||||
@@ -352,4 +338,15 @@ class AssetFactory extends Factory
|
||||
{
|
||||
return $this->state(['requestable' => false]);
|
||||
}
|
||||
|
||||
public function withComplicatedCustomFields()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'model_id' => function () {
|
||||
return AssetModel::where('name','complicated')->first() ?? AssetModel::factory()->complicated();
|
||||
}
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use App\Models\Depreciation;
|
||||
use App\Models\Manufacturer;
|
||||
@@ -429,4 +430,13 @@ class AssetModelFactory extends Factory
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function complicated()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'name' => 'Complicated fieldset'
|
||||
];
|
||||
})->for(CustomFieldSet::factory()->complicated(),'fieldset');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class CompanyFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->company(),
|
||||
'name' => $this->faker->company(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ class CustomFieldFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
'format' => '',
|
||||
'element' => 'text',
|
||||
'auto_add_to_fieldsets' => '0',
|
||||
'type' => 'App\\Models\\Asset'
|
||||
];
|
||||
}
|
||||
|
||||
@@ -74,9 +75,28 @@ class CustomFieldFactory extends Factory
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'name' => 'MAC Address',
|
||||
'name' => 'MAC Address EXPLICIT',
|
||||
'format' => 'regex:/^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/',
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function plainText()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'name' => 'plain_text',
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function date()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'name' => 'date',
|
||||
'format' => 'date'
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
@@ -22,7 +23,7 @@ class CustomFieldsetFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -43,4 +44,16 @@ class CustomFieldsetFactory extends Factory
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function complicated()
|
||||
{
|
||||
//$mac = CustomField::factory()->macAddress()->create();
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'name' => 'complicated'
|
||||
];
|
||||
}) ->hasAttached(CustomField::factory()->macAddress(),['required' => false, 'order' => 0],'fields')
|
||||
->hasAttached(CustomField::factory()->plainText(),['required' => true,'order' => 1],'fields')
|
||||
->hasAttached(CustomField::factory()->date(),['required' => false, 'order' => 2],'fields');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class DepreciationFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
'user_id' => User::factory()->superuser(),
|
||||
'months' => 36,
|
||||
];
|
||||
|
||||
@@ -23,7 +23,7 @@ class ManufacturerFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->company(),
|
||||
'name' => $this->faker->company(),
|
||||
'user_id' => User::factory()->superuser(),
|
||||
'support_phone' => $this->faker->phoneNumber(),
|
||||
'url' => $this->faker->url(),
|
||||
|
||||
@@ -33,11 +33,11 @@ class UserFactory extends Factory
|
||||
'permissions' => '{}',
|
||||
'phone' => $this->faker->phoneNumber(),
|
||||
'state' => $this->faker->stateAbbr(),
|
||||
'username' => $this->faker->unique()->username(),
|
||||
'username' => $this->faker->username(),
|
||||
'zip' => $this->faker->postcode(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function firstAdmin()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user