Compare commits
467 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7af049589 | |||
| c2d863da99 | |||
| 6f9ba6ede4 | |||
| df4e6a0023 | |||
| d60fa65f85 | |||
| 8081a82fe4 | |||
| f42e5d5292 | |||
| 5a3f5b03d0 | |||
| 2b4886f37f | |||
| b45de3e17f | |||
| b2eea3e5a5 | |||
| f411c0fdd8 | |||
| 74d8431d01 | |||
| 3ea0cd75a5 | |||
| 5f6c746d25 | |||
| 1f2d30ebf4 | |||
| 6dd6b45829 | |||
| e5800a2dac | |||
| 0d3d172108 | |||
| 86677b5f13 | |||
| 3f5b94f8ad | |||
| cf8cb8521b | |||
| ccd00caa70 | |||
| 57010b4c23 | |||
| 545a185614 | |||
| 1572e339f9 | |||
| 7782e5cc93 | |||
| 3bb81d1e4d | |||
| 756c44fcba | |||
| befa4428d0 | |||
| 60c678680a | |||
| 8bc9688d71 | |||
| b124b9af4d | |||
| ae403da8c1 | |||
| b5b8777c94 | |||
| 850f85ff59 | |||
| 84cc88831d | |||
| f4f9b165a7 | |||
| 3222d4c8df | |||
| 3173ead2e7 | |||
| 89d733d442 | |||
| df49e8350f | |||
| 3ced85080a | |||
| 0611ab9b4c | |||
| f450cafe3e | |||
| 1f29eb1875 | |||
| a4e5ae0938 | |||
| 77dacfcc30 | |||
| 0d9b6eaf71 | |||
| 7060ffaf34 | |||
| 02a37e2f89 | |||
| 9c1b1bc2b5 | |||
| b34156ca25 | |||
| 61bdb57b5d | |||
| 9df84e235c | |||
| 566ba4783e | |||
| b41b4b1732 | |||
| ccf9457c45 | |||
| 53aabdab66 | |||
| 8ff85c952e | |||
| afe1cb8234 | |||
| bd42505799 | |||
| 6c735c97c6 | |||
| 31a57cdf14 | |||
| 7ebbef25e7 | |||
| f836342194 | |||
| 5cf1a6c300 | |||
| bd506820b7 | |||
| 5815607924 | |||
| 9b40c9788f | |||
| 67b5e9093e | |||
| 57d1c036ec | |||
| 71722b753d | |||
| a2625c889a | |||
| c98b9da612 | |||
| 675717ff82 | |||
| 83ef7c6fe8 | |||
| 5f4c964309 | |||
| 66ba96d531 | |||
| d67b2da064 | |||
| e45fd4088f | |||
| 7e4a0eedf0 | |||
| 3f812f696d | |||
| e9e6f925bf | |||
| 828b84084d | |||
| a6a0bfacc2 | |||
| c4b7e77498 | |||
| 91c7180bfd | |||
| 7c39f516b9 | |||
| ce1ddcfcee | |||
| 945e8b402f | |||
| 5ed2bd0fb7 | |||
| bc908b854d | |||
| 2067b1138a | |||
| 1ffbdee156 | |||
| bd2812cac1 | |||
| f2a5eac256 | |||
| b4e647dbd1 | |||
| de18e449a6 | |||
| dce19e0bea | |||
| 1f586d3102 | |||
| e5d01170d2 | |||
| 0f11963127 | |||
| d8378f2a10 | |||
| a0a5480c97 | |||
| 3391108551 | |||
| 52551dad0f | |||
| 321414f6e3 | |||
| 7787fe42c8 | |||
| 3b66912742 | |||
| 278a25c63b | |||
| 0d124bb5a1 | |||
| 417caae589 | |||
| 3d306aacc5 | |||
| ea4ecaea03 | |||
| 6c90f9e395 | |||
| ddf81ba135 | |||
| 8ebb41caa6 | |||
| faf48b1684 | |||
| b8232d205b | |||
| 62745923cf | |||
| 090466123f | |||
| 38a3e36cd6 | |||
| e8dc634a40 | |||
| 0d0984a400 | |||
| 8640cad033 | |||
| dc29717623 | |||
| 814914924f | |||
| c7083488b2 | |||
| 4b4d383509 | |||
| 3680e04817 | |||
| 21e23baa37 | |||
| fcd130ae15 | |||
| d1dffb84dc | |||
| 541350916d | |||
| 002fd4ce30 | |||
| 7b4ecb275f | |||
| 2df5d3a8ff | |||
| 7070bad53b | |||
| da62d6af26 | |||
| d0d4d14787 | |||
| 09d69b214b | |||
| 0e2aaebda4 | |||
| ec2c58163f | |||
| a28bee86ba | |||
| fb64892971 | |||
| 95ff692b14 | |||
| 8003615b1f | |||
| 948dc3c974 | |||
| 1afb724606 | |||
| 451281d833 | |||
| 485f11c945 | |||
| dbc79655b0 | |||
| 02f6aa6161 | |||
| 07c5264b41 | |||
| 7c178a6a78 | |||
| f56d53d7c1 | |||
| 4cd4a936d8 | |||
| 7bae4c39c6 | |||
| d55d95bbea | |||
| 5e48d56561 | |||
| 6a5098fb0c | |||
| 4e835e1772 | |||
| cce8cb4f5e | |||
| 8aed26aab1 | |||
| 01d5d4c2c8 | |||
| 592385cb07 | |||
| 85123b3e66 | |||
| 0fcf223960 | |||
| bf0bd06f20 | |||
| f07b0b6bd7 | |||
| 717b26c834 | |||
| 8bb8eab69b | |||
| 693d1c9452 | |||
| b049bb1d5c | |||
| c5c6b3bbc6 | |||
| 1df56a7cab | |||
| 3f5cc2507d | |||
| 5a85424295 | |||
| a53a8cca74 | |||
| 3fdee881f9 | |||
| a289dfaf88 | |||
| 8abd359b5b | |||
| 9359809b4f | |||
| cde5502f94 | |||
| 04e0a9d4a5 | |||
| 28ec0b8ebb | |||
| 37dfecf098 | |||
| 9d8ce872a4 | |||
| 07880dfe50 | |||
| 7eed9f8542 | |||
| a2e70dd6b2 | |||
| b9aeded957 | |||
| 027361f079 | |||
| ff10d1540f | |||
| 0f63fa23e0 | |||
| 22ef569e5e | |||
| f3663f0983 | |||
| 112ddaf55b | |||
| bda6fdf09c | |||
| a62198f33f | |||
| 4b0bfc52b4 | |||
| 78868813b1 | |||
| e8be178ac7 | |||
| 695428cd44 | |||
| 9ae779e442 | |||
| db92febdc7 | |||
| 5cf10cec34 | |||
| ea2d54b0f7 | |||
| c66267a0f9 | |||
| f1d2f24534 | |||
| d83974e07f | |||
| f270f30728 | |||
| 55c237913c | |||
| 806671df7c | |||
| d64ee42ec3 | |||
| fe08f39900 | |||
| 5123ab57c9 | |||
| 313b327cd7 | |||
| 855d922a3e | |||
| cbe07ad23b | |||
| b3aba4ad99 | |||
| 21ad7f549d | |||
| 4b13fa45c5 | |||
| 485d40c752 | |||
| 8346ae8235 | |||
| 109c0f202a | |||
| 4231058aa1 | |||
| 6156d67e4a | |||
| 58bf036f52 | |||
| ff7d25c0f2 | |||
| 5f0b7f328c | |||
| 6559581bad | |||
| d78262f52b | |||
| bd566324ed | |||
| b65bf5082d | |||
| 939e4cba3e | |||
| 015a8763a0 | |||
| 02862d80eb | |||
| 7b0a3fc6d3 | |||
| b40b31b7b1 | |||
| 149d3d13d1 | |||
| 0f64d66cd8 | |||
| a85e2f7aad | |||
| 4f883b1264 | |||
| feb78d00cf | |||
| c9d54baa10 | |||
| 940f54dab1 | |||
| d83827a44e | |||
| 3a0a13d06d | |||
| 23f8e35716 | |||
| a251e61d73 | |||
| af06b1cd06 | |||
| 7769a93a10 | |||
| 95a6c7058f | |||
| 6c3a668400 | |||
| ad0f873ece | |||
| 3008a4ed7a | |||
| 95ef3a336b | |||
| 9a5c1b8126 | |||
| e926db76a0 | |||
| 9419c7fdeb | |||
| 9dbb4abe7e | |||
| 19e0fb7955 | |||
| 5b9b21a7d1 | |||
| 93e69ab0c6 | |||
| bc5c559413 | |||
| 9b2fcbff08 | |||
| ad2674d20b | |||
| 10ac2c830f | |||
| df3053eafb | |||
| aaae952acb | |||
| eb0657c953 | |||
| b1cd44341b | |||
| 3da47cdacd | |||
| 658dda916c | |||
| 7c3d8b896b | |||
| 1ce9df7998 | |||
| a0cbf66c81 | |||
| a4941031cb | |||
| 9fd6aea325 | |||
| a52181c995 | |||
| ee75df0f0a | |||
| 92eff653f1 | |||
| 1e66985a78 | |||
| a059a42799 | |||
| b5603fbfe9 | |||
| a0423a9cc3 | |||
| 4ab7112988 | |||
| 767cf96010 | |||
| 4ffb7790df | |||
| 3ccc55a78f | |||
| d0d29e03db | |||
| 92b7c4b5ec | |||
| dff7c43aed | |||
| 9efbcbbd5e | |||
| 31fa0a7044 | |||
| fcb2bf7fea | |||
| 0bd27d61b0 | |||
| 369ecfa490 | |||
| 551354b1bb | |||
| 03b7891edc | |||
| 8978dff054 | |||
| d20844fefa | |||
| cd579a04dd | |||
| 15b8140bff | |||
| 9a93ad2e06 | |||
| bd4d3aa52b | |||
| bf32ab177f | |||
| 2ea883aa15 | |||
| 43cc296582 | |||
| 4c1aadd74e | |||
| 7d3719bf70 | |||
| c08164d864 | |||
| b156aa74a5 | |||
| 87ba2cb407 | |||
| 5084e5d3ef | |||
| a5516e3511 | |||
| 0e460baf82 | |||
| ef52777ffb | |||
| b67ceab849 | |||
| 69022bb8b6 | |||
| 29d729171c | |||
| 9475871edb | |||
| b69364d5ff | |||
| 10dad8e6e6 | |||
| a184b4e67c | |||
| 8cd0a90ecd | |||
| 4a37632ef3 | |||
| 3271d020e9 | |||
| e494a2670f | |||
| d3a0a337b9 | |||
| 3951ee746d | |||
| 84e4257e75 | |||
| c401c88702 | |||
| 550f9e2afa | |||
| b55a19cebb | |||
| 4caadcfa19 | |||
| dba837b1d2 | |||
| 714fc63050 | |||
| b6fa6cba22 | |||
| 2df026bcb5 | |||
| 6ee24a7527 | |||
| e2dcee1959 | |||
| 4fbea9512f | |||
| b7850ab839 | |||
| c0215baca5 | |||
| c62758c5b5 | |||
| 14358651e4 | |||
| f04aeb9f2b | |||
| dc902e7a5a | |||
| 4fc66e19bb | |||
| e12d2b2a42 | |||
| cb78451d6c | |||
| 7979bc63ae | |||
| e8ad8a7448 | |||
| eb61f5aa9e | |||
| 3351998efd | |||
| 20dbacd22f | |||
| 0f3be4fdf8 | |||
| 3ae8adfbf9 | |||
| aa2632fe46 | |||
| 14c86d447b | |||
| bee016e0be | |||
| 54552fc95c | |||
| ffa7d25fc0 | |||
| a37d3b00d0 | |||
| 04891c7c61 | |||
| d67ff54f4b | |||
| ccec190985 | |||
| 26728a85ad | |||
| c6d85a1b0b | |||
| 71610fb20f | |||
| cb0f9024b1 | |||
| 1797480128 | |||
| 972b198248 | |||
| 9010b7acd0 | |||
| b57b68571e | |||
| 1ca9420baa | |||
| 0383938536 | |||
| 50b841d54d | |||
| 8f71460fa1 | |||
| d5324bce6a | |||
| 660f3ccba1 | |||
| bc8db3deab | |||
| b2c8fbf349 | |||
| c3f21d9292 | |||
| 9b146ae1d2 | |||
| a32c679519 | |||
| 1e602793b2 | |||
| a6a65b7523 | |||
| 04c1d9cbff | |||
| a6dfd67cd7 | |||
| 7d178da61c | |||
| 30f9acfcf3 | |||
| 1e351b4d63 | |||
| cb5b691ec1 | |||
| b47b401245 | |||
| 119e79e248 | |||
| d7254053b6 | |||
| 8f8edd4126 | |||
| 10bb844087 | |||
| ba3baabb50 | |||
| c76fbe4edb | |||
| cae2de4fc9 | |||
| 7c346d977a | |||
| 9847934de9 | |||
| db73f80058 | |||
| 4dd479dad7 | |||
| d01e1e8eeb | |||
| e3ef737ac4 | |||
| 69317fb403 | |||
| 1b80c8938a | |||
| dc77c01fd3 | |||
| 83474d6e59 | |||
| 529310c93a | |||
| 70f26f33a5 | |||
| 414bc10c40 | |||
| 250b0a7afb | |||
| e5355db672 | |||
| aef45a90b2 | |||
| 6a78706a3e | |||
| 232fad0145 | |||
| 5cbcac28b1 | |||
| aec59f2da6 | |||
| 905df5ec25 | |||
| bacfdc5049 | |||
| 3cc72021b6 | |||
| 115e0fc119 | |||
| 4354e126b1 | |||
| 02f39472f9 | |||
| d7aed2edc9 | |||
| af513946a2 | |||
| 7bfd02054b | |||
| 1ceb703129 | |||
| fb28882f65 | |||
| d9c61fdb02 | |||
| 72c118a70f | |||
| 25241542d2 | |||
| 57a75e68b9 | |||
| ad1846fed6 | |||
| dcf2168454 | |||
| 9ab56fe9ca | |||
| f708b8b299 | |||
| c5e8d1c276 | |||
| 4093327b7f | |||
| 391b832613 | |||
| b653d19579 | |||
| 4a57cfaf3e | |||
| 31a75bd252 | |||
| 0506f3bef9 | |||
| 852b0b3f11 | |||
| 307b39bd38 | |||
| d55358652b | |||
| 955f75f733 | |||
| 70ef904951 | |||
| fcf023e3d2 | |||
| 8c882ddead | |||
| 7d136f9970 | |||
| c81bc1d2ee | |||
| bcfa913450 | |||
| 43d8474caa | |||
| 51ae485f20 | |||
| 1248260df3 | |||
| 4cb804cf03 | |||
| 2b0dd8851c | |||
| 41e0275c95 |
@@ -86,6 +86,7 @@ COOKIE_DOMAIN=null
|
||||
SECURE_COOKIES=false
|
||||
API_TOKEN_EXPIRATION_YEARS=15
|
||||
BS_TABLE_STORAGE=cookieStorage
|
||||
BS_TABLE_DEEPLINK=true
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||
|
||||
@@ -29,6 +29,7 @@ RUN apk add --no-cache \
|
||||
php81-sodium \
|
||||
php81-redis \
|
||||
php81-pecl-memcached \
|
||||
php81-exif \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||

|
||||
|
||||
[](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) [](https://github.com/snipe/snipe-it/actions/workflows/tests.yml)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk)
|
||||
[](#contributing) [](https://discord.gg/yZFtShAcKk)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
||||
@@ -11,7 +11,8 @@ It is built on [Laravel 8](http://laravel.com).
|
||||
|
||||
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
||||
|
||||
__This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
|
||||
> [!TIP]
|
||||
> __This is web-based software__. This means there is no executable file (aka no .exe files), and it must be run on a web server and accessed through a web browser. It runs on any Mac OSX, flavor of Linux, as well as Windows, and we have a [Docker image](https://snipe-it.readme.io/docs/docker) available if that's what you're into.
|
||||
|
||||
-----
|
||||
|
||||
@@ -21,7 +22,7 @@ For instructions on installing and configuring Snipe-IT on your server, check ou
|
||||
|
||||
If you're having trouble with the installation, please check the [Common Issues](https://snipe-it.readme.io/docs/common-issues) and [Getting Help](https://snipe-it.readme.io/docs/getting-help) documentation, and search this repository's open *and* closed issues for help.
|
||||
|
||||
[](https://heroku.com/deploy)
|
||||
<!-- [](https://heroku.com/deploy) -->
|
||||
|
||||
-----
|
||||
### User's Manual
|
||||
@@ -32,8 +33,9 @@ For help using Snipe-IT, check out the [user's manual](https://snipe-it.readme.i
|
||||
|
||||
Feel free to check out the [GitHub Issues for this project](https://github.com/snipe/snipe-it/issues) to open a bug report or see what open issues you can help with. Please search through existing issues (open *and* closed) to see if your question has already been answered before opening a new issue.
|
||||
|
||||
**PLEASE see the [Getting Help Guidelines](https://snipe-it.readme.io/docs/getting-help) and [Common Issues](https://snipe-it.readme.io/docs/common-issues) before opening a ticket, and be sure to complete all of the questions in the Github Issue template to help us to help you as quickly as possible.**
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **PLEASE see the [Getting Help Guidelines](https://snipe-it.readme.io/docs/getting-help) and [Common Issues](https://snipe-it.readme.io/docs/common-issues) before opening a ticket, and be sure to complete all of the questions in the Github Issue template to help us to help you as quickly as possible.**
|
||||
>
|
||||
-----
|
||||
|
||||
### Upgrading
|
||||
@@ -57,6 +59,9 @@ Please see the [translations documentation](https://snipe-it.readme.io/docs/tran
|
||||
|
||||
Since the release of the JSON REST API, several third-party developers have been developing modules and libraries to work with Snipe-IT.
|
||||
|
||||
> [!NOTE]
|
||||
> As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
|
||||
|
||||
- [Python Module](https://github.com/jbloomer/SnipeIT-PythonAPI) by [@jbloomer](https://github.com/jbloomer)
|
||||
- [SnipeSharp - .NET module in C#](https://github.com/barrycarey/SnipeSharp) by [@barrycarey](https://github.com/barrycarey)
|
||||
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
|
||||
@@ -73,8 +78,6 @@ Since the release of the JSON REST API, several third-party developers have been
|
||||
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
|
||||
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
|
||||
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
|
||||
|
||||
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)
|
||||
|
||||
-----
|
||||
|
||||
@@ -92,4 +95,5 @@ The ERD is available [online here](https://drawsql.app/templates/snipe-it).
|
||||
|
||||
### Security
|
||||
|
||||
To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.
|
||||
> [!IMPORTANT]
|
||||
> **To report a security vulnerability, please email security@snipeitapp.com instead of using the issue tracker.**
|
||||
|
||||
@@ -5,6 +5,151 @@ namespace App\Console\Commands;
|
||||
use Illuminate\Console\Command;
|
||||
use ZipArchive;
|
||||
|
||||
class SQLStreamer {
|
||||
private $input;
|
||||
private $output;
|
||||
// embed the prefix here?
|
||||
public ?string $prefix;
|
||||
|
||||
private bool $reading_beginning_of_line = true;
|
||||
|
||||
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
||||
|
||||
public array $tablenames = [];
|
||||
private bool $should_guess = false;
|
||||
private bool $statement_is_permitted = false;
|
||||
|
||||
public function __construct($input, $output, string $prefix = null)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function parse_sql(string $line): string {
|
||||
// take into account the 'start of line or not' setting as an instance variable?
|
||||
// 'continuation' lines for a permitted statement are PERMITTED.
|
||||
if($this->statement_is_permitted && $line[0] === ' ') {
|
||||
return $line;
|
||||
}
|
||||
|
||||
$table_regex = '`?([a-zA-Z0-9_]+)`?';
|
||||
$allowed_statements = [
|
||||
"/^(DROP TABLE (?:IF EXISTS )?)`$table_regex(.*)$/" => false,
|
||||
"/^(CREATE TABLE )$table_regex(.*)$/" => true, //sets up 'continuation'
|
||||
"/^(LOCK TABLES )$table_regex(.*)$/" => false,
|
||||
"/^(INSERT INTO )$table_regex(.*)$/" => false,
|
||||
"/^UNLOCK TABLES/" => false,
|
||||
// "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here?
|
||||
"/^\\)[a-zA-Z0-9_= ]*;$/" => false
|
||||
// ^^^^^^ that bit should *exit* the 'perimitted' black
|
||||
];
|
||||
|
||||
foreach($allowed_statements as $statement => $statechange) {
|
||||
// $this->info("Checking regex: $statement...\n");
|
||||
$matches = [];
|
||||
if (preg_match($statement,$line,$matches)) {
|
||||
$this->statement_is_permitted = $statechange;
|
||||
// matches are: 1 => first part of the statement, 2 => tablename, 3 => rest of statement
|
||||
// (with of course 0 being "the whole match")
|
||||
if (@$matches[2]) {
|
||||
// print "Found a tablename! It's: ".$matches[2]."\n";
|
||||
if ($this->should_guess) {
|
||||
@$this->tablenames[$matches[2]] += 1;
|
||||
continue; //oh? FIXME
|
||||
} else {
|
||||
$cleaned_tablename = \DB::getTablePrefix().preg_replace('/^'.$this->prefix.'/','',$matches[2]);
|
||||
$line = preg_replace($statement,'$1`'.$cleaned_tablename.'`$3' , $line);
|
||||
}
|
||||
} else {
|
||||
// no explicit tablename in this one, leave the line alone
|
||||
}
|
||||
//how do we *replace* the tablename?
|
||||
// print "RETURNING LINE: $line";
|
||||
return $line;
|
||||
}
|
||||
}
|
||||
// all that is not allowed is denied.
|
||||
return "";
|
||||
}
|
||||
|
||||
//this is used in exactly *TWO* places, and in both cases should return a prefix I think?
|
||||
// first - if you do the --sanitize-only one (which is mostly for testing/development)
|
||||
// next - when you run *without* a guessed prefix, this is run first to figure out the prefix
|
||||
// I think we have to *duplicate* the call to be able to run it again?
|
||||
public static function guess_prefix($input):string
|
||||
{
|
||||
$parser = new self($input, null);
|
||||
$parser->should_guess = true;
|
||||
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
|
||||
|
||||
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
|
||||
//can't use 'users' because the 'accessories_users' table?
|
||||
// can't use 'assets' because 'ver1_components_assets'
|
||||
foreach($check_tables as $check_table => $_ignore) {
|
||||
foreach ($parser->tablenames as $tablename => $_count) {
|
||||
// print "Comparing $tablename to $check_table\n";
|
||||
if (str_ends_with($tablename,$check_table)) {
|
||||
// print "Found one!\n";
|
||||
$check_tables[$check_table] = substr($tablename,0,-strlen($check_table));
|
||||
}
|
||||
}
|
||||
}
|
||||
$guessed_prefix = null;
|
||||
foreach ($check_tables as $clean_table => $prefix_guess) {
|
||||
if(is_null($prefix_guess)) {
|
||||
print("Couldn't find table $clean_table\n");
|
||||
die();
|
||||
}
|
||||
if(is_null($guessed_prefix)) {
|
||||
$guessed_prefix = $prefix_guess;
|
||||
} else {
|
||||
if ($guessed_prefix != $prefix_guess) {
|
||||
print("Prefix mismatch! Had guessed $guessed_prefix but got $prefix_guess\n");
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $guessed_prefix;
|
||||
|
||||
}
|
||||
|
||||
public function line_aware_piping(): int
|
||||
{
|
||||
$bytes_read = 0;
|
||||
if (! $this->input) {
|
||||
throw new \Exception("No Input available for line_aware_piping");
|
||||
}
|
||||
|
||||
while (($buffer = fgets($this->input, SQLStreamer::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
if ($this->reading_beginning_of_line) {
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$cleaned_buffer = $this->parse_sql($buffer);
|
||||
if ($this->output) {
|
||||
$bytes_written = fwrite($this->output, $cleaned_buffer);
|
||||
|
||||
if ($bytes_written === false) {
|
||||
throw new \Exception("Unable to write to pipe");
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we got a newline at the end of this, then the _next_ read is the beginning of a line
|
||||
if($buffer[strlen($buffer)-1] === "\n") {
|
||||
$this->reading_beginning_of_line = true;
|
||||
} else {
|
||||
$this->reading_beginning_of_line = false;
|
||||
}
|
||||
|
||||
}
|
||||
return $bytes_read;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class RestoreFromBackup extends Command
|
||||
{
|
||||
/**
|
||||
@@ -12,10 +157,13 @@ class RestoreFromBackup extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
// FIXME - , stripping prefixes and nonstandard SQL statements. Without --prefix, guess and return the correct prefix to strip
|
||||
protected $signature = 'snipeit:restore
|
||||
{--force : Skip the danger prompt; assuming you enter "y"}
|
||||
{filename : The zip file to be migrated}
|
||||
{--no-progress : Don\'t show a progress bar}';
|
||||
{--no-progress : Don\'t show a progress bar}
|
||||
{--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL}
|
||||
{--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -34,8 +182,6 @@ class RestoreFromBackup extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
@@ -55,7 +201,7 @@ class RestoreFromBackup extends Command
|
||||
return $this->error('Missing required filename');
|
||||
}
|
||||
|
||||
if (! $this->option('force') && ! $this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
|
||||
if (! $this->option('force') && ! $this->option('sanitize-guess-prefix') && ! $this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
|
||||
return $this->error('Data loss not confirmed');
|
||||
}
|
||||
|
||||
@@ -158,11 +304,11 @@ class RestoreFromBackup extends Command
|
||||
}
|
||||
|
||||
foreach (array_merge($private_dirs, $public_dirs) as $dir) {
|
||||
$last_pos = strrpos($raw_path, $dir.'/');
|
||||
$last_pos = strrpos($raw_path, $dir . '/');
|
||||
if ($last_pos !== false) {
|
||||
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
|
||||
//print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
|
||||
$interesting_files[$raw_path] = ['dest' =>$dir, 'index' => $i];
|
||||
$interesting_files[$raw_path] = ['dest' => $dir, 'index' => $i];
|
||||
continue 2;
|
||||
if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) {
|
||||
// we don't care about that; we just want files with the appropriate prefix
|
||||
@@ -171,7 +317,7 @@ class RestoreFromBackup extends Command
|
||||
}
|
||||
}
|
||||
$good_extensions = ['png', 'gif', 'jpg', 'svg', 'jpeg', 'doc', 'docx', 'pdf', 'txt',
|
||||
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico', ];
|
||||
'zip', 'rar', 'xls', 'xlsx', 'lic', 'xml', 'rtf', 'webp', 'key', 'ico',];
|
||||
foreach (array_merge($private_files, $public_files) as $file) {
|
||||
$has_wildcard = (strpos($file, '*') !== false);
|
||||
if ($has_wildcard) {
|
||||
@@ -180,8 +326,8 @@ class RestoreFromBackup extends Command
|
||||
$last_pos = strrpos($raw_path, $file); // no trailing slash!
|
||||
if ($last_pos !== false) {
|
||||
$extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION));
|
||||
if (! in_array($extension, $good_extensions)) {
|
||||
$this->warn('Potentially unsafe file '.$raw_path.' is being skipped');
|
||||
if (!in_array($extension, $good_extensions)) {
|
||||
$this->warn('Potentially unsafe file ' . $raw_path . ' is being skipped');
|
||||
$boring_files[] = $raw_path;
|
||||
continue 2;
|
||||
}
|
||||
@@ -196,7 +342,6 @@ class RestoreFromBackup extends Command
|
||||
}
|
||||
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
|
||||
} // end of pre-processing the ZIP file for-loop
|
||||
|
||||
// print_r($interesting_files);exit(-1);
|
||||
|
||||
if (count($sqlfiles) != 1) {
|
||||
@@ -208,6 +353,17 @@ class RestoreFromBackup extends Command
|
||||
//older Snipe-IT installs don't have the db-dumps subdirectory component
|
||||
}
|
||||
|
||||
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
||||
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
||||
$sql_contents = $za->getStream($sql_stat['name']); // maybe copy *THIS* thing?
|
||||
|
||||
// OKAY, now that we *found* the sql file if we're doing just the guess-prefix thing, we can do that *HERE* I think?
|
||||
if ($this->option('sanitize-guess-prefix')) {
|
||||
$prefix = SQLStreamer::guess_prefix($sql_contents);
|
||||
$this->line($prefix);
|
||||
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
||||
}
|
||||
|
||||
//how to invoke the restore?
|
||||
$pipes = [];
|
||||
|
||||
@@ -228,6 +384,7 @@ class RestoreFromBackup extends Command
|
||||
return $this->error('Unable to invoke mysql via CLI');
|
||||
}
|
||||
|
||||
// I'm not sure about these?
|
||||
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
||||
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
||||
|
||||
@@ -238,9 +395,9 @@ class RestoreFromBackup extends Command
|
||||
|
||||
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
|
||||
|
||||
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
||||
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
||||
$sql_contents = $za->getStream($sql_stat['name']);
|
||||
// FIXME - this feels like it wants to go somewhere else?
|
||||
// and it doesn't seem 'right' - if you can't get a stream to the .sql file,
|
||||
// why do we care what's happening with pipes and stdout and stderr?!
|
||||
if ($sql_contents === false) {
|
||||
$stdout = fgets($pipes[1]);
|
||||
$this->info($stdout);
|
||||
@@ -249,20 +406,27 @@ class RestoreFromBackup extends Command
|
||||
|
||||
return false;
|
||||
}
|
||||
$bytes_read = 0;
|
||||
|
||||
try {
|
||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
if ( $this->option('sanitize-with-prefix') === null) {
|
||||
// "Legacy" direct-piping
|
||||
$bytes_read = 0;
|
||||
while (($buffer = fgets($sql_contents, SQLStreamer::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$bytes_written = fwrite($pipes[0], $buffer);
|
||||
|
||||
if ($bytes_written === false) {
|
||||
throw new Exception("Unable to write to pipe");
|
||||
if ($bytes_written === false) {
|
||||
throw new Exception("Unable to write to pipe");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$sql_importer = new SQLStreamer($sql_contents, $pipes[0], $this->option('sanitize-with-prefix'));
|
||||
$bytes_read = $sql_importer->line_aware_piping();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
||||
// FIXME - put these back and/or put them in the right places?!
|
||||
$err_out = fgets($pipes[1]);
|
||||
$err_err = fgets($pipes[2]);
|
||||
\Log::error("Error OUTPUT: ".$err_out);
|
||||
@@ -271,7 +435,6 @@ class RestoreFromBackup extends Command
|
||||
$this->error($err_err);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!feof($sql_contents) || $bytes_read == 0) {
|
||||
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
||||
}
|
||||
@@ -303,7 +466,7 @@ class RestoreFromBackup extends Command
|
||||
$fp = $za->getStream($ugly_file_name);
|
||||
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
||||
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
||||
while (($buffer = fgets($fp, self::$buffer_size)) !== false) {
|
||||
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
|
||||
fwrite($migrated_file, $buffer);
|
||||
}
|
||||
fclose($migrated_file);
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ToggleCustomfieldEncryption extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:customfield-encryption
|
||||
{fieldname : the db_column_name of the field}';
|
||||
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This command should be used to convert an unencrypted custom field into a custom field and encrypt the associated data in the assets table for that column.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$fieldname = $this->argument('fieldname');
|
||||
|
||||
if ($field = CustomField::where('db_column', $fieldname)->first()) {
|
||||
|
||||
// If the field is not encrypted, make it encrypted and encrypt the data in the assets table for the
|
||||
// corresponding field.
|
||||
DB::transaction(function () use ($field) {
|
||||
|
||||
if ($field->field_encrypted == 0) {
|
||||
$assets = Asset::whereNotNull($field->db_column)->get();
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
$asset->{$field->db_column} = encrypt($asset->{$field->db_column});
|
||||
$asset->save();
|
||||
}
|
||||
|
||||
$field->field_encrypted = 1;
|
||||
$field->save();
|
||||
|
||||
// This field is already encrypted. Do nothing.
|
||||
} else {
|
||||
$this->error('The custom field ' . $field->db_column.' is already encrypted. No action was taken.');
|
||||
}
|
||||
});
|
||||
|
||||
// No matching column name found
|
||||
} else {
|
||||
$this->error('No matching results for unencrypted custom fields with db_column name: ' . $fieldname.'. Please check the fieldname.');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+32
-6
@@ -11,6 +11,7 @@ use App\Models\CustomFieldset;
|
||||
use App\Models\Depreciation;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\License;
|
||||
use Crypt;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Image;
|
||||
@@ -715,18 +716,19 @@ class Helper
|
||||
*/
|
||||
public static function checkLowInventory()
|
||||
{
|
||||
$alert_threshold = \App\Models\Setting::getSettings()->alert_threshold;
|
||||
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
|
||||
$accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get();
|
||||
$components = Component::whereNotNull('min_amt')->get();
|
||||
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
|
||||
$licenses = License::where('min_amt', '>', 0)->get();
|
||||
|
||||
$avail_consumables = 0;
|
||||
$items_array = [];
|
||||
$all_count = 0;
|
||||
|
||||
foreach ($consumables as $consumable) {
|
||||
$avail = $consumable->numRemaining();
|
||||
if ($avail < ($consumable->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
||||
if ($avail < ($consumable->min_amt) + $alert_threshold) {
|
||||
if ($consumable->qty > 0) {
|
||||
$percent = number_format((($avail / $consumable->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -745,7 +747,7 @@ class Helper
|
||||
|
||||
foreach ($accessories as $accessory) {
|
||||
$avail = $accessory->qty - $accessory->users_count;
|
||||
if ($avail < ($accessory->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
||||
if ($avail < ($accessory->min_amt) + $alert_threshold) {
|
||||
if ($accessory->qty > 0) {
|
||||
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -764,7 +766,7 @@ class Helper
|
||||
|
||||
foreach ($components as $component) {
|
||||
$avail = $component->numRemaining();
|
||||
if ($avail < ($component->min_amt) + \App\Models\Setting::getSettings()->alert_threshold) {
|
||||
if ($avail < ($component->min_amt) + $alert_threshold) {
|
||||
if ($component->qty > 0) {
|
||||
$percent = number_format((($avail / $component->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -787,7 +789,7 @@ class Helper
|
||||
$total_owned = $asset->where('model_id', '=', $asset_model->id)->count();
|
||||
$avail = $asset->where('model_id', '=', $asset_model->id)->whereNull('assigned_to')->count();
|
||||
|
||||
if ($avail < ($asset_model->min_amt)+ \App\Models\Setting::getSettings()->alert_threshold) {
|
||||
if ($avail < ($asset_model->min_amt) + $alert_threshold) {
|
||||
if ($avail > 0) {
|
||||
$percent = number_format((($avail / $total_owned) * 100), 0);
|
||||
} else {
|
||||
@@ -803,6 +805,26 @@ class Helper
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($licenses as $license){
|
||||
$avail = $license->remaincount();
|
||||
if ($avail < ($license->min_amt) + $alert_threshold) {
|
||||
if ($avail > 0) {
|
||||
$percent = number_format((($avail / $license->min_amt) * 100), 0);
|
||||
} else {
|
||||
$percent = 100;
|
||||
}
|
||||
|
||||
$items_array[$all_count]['id'] = $license->id;
|
||||
$items_array[$all_count]['name'] = $license->name;
|
||||
$items_array[$all_count]['type'] = 'licenses';
|
||||
$items_array[$all_count]['percent'] = $percent;
|
||||
$items_array[$all_count]['remaining'] = $avail;
|
||||
$items_array[$all_count]['min_amt'] = $license->min_amt;
|
||||
$all_count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $items_array;
|
||||
}
|
||||
|
||||
@@ -820,7 +842,7 @@ class Helper
|
||||
$filetype = @finfo_file($finfo, $file);
|
||||
finfo_close($finfo);
|
||||
|
||||
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif')) {
|
||||
if (($filetype == 'image/jpeg') || ($filetype == 'image/jpg') || ($filetype == 'image/png') || ($filetype == 'image/bmp') || ($filetype == 'image/gif') || ($filetype == 'image/avif')) {
|
||||
return $filetype;
|
||||
}
|
||||
|
||||
@@ -1084,6 +1106,8 @@ class Helper
|
||||
'jpeg' => 'far fa-image',
|
||||
'gif' => 'far fa-image',
|
||||
'png' => 'far fa-image',
|
||||
'webp' => 'far fa-image',
|
||||
'avif' => 'far fa-image',
|
||||
// word
|
||||
'doc' => 'far fa-file-word',
|
||||
'docx' => 'far fa-file-word',
|
||||
@@ -1119,6 +1143,8 @@ class Helper
|
||||
case 'jpeg':
|
||||
case 'gif':
|
||||
case 'png':
|
||||
case 'webp':
|
||||
case 'avif':
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Http\Requests\StoreAssetRequest;
|
||||
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -45,6 +49,8 @@ use Route;
|
||||
*/
|
||||
class AssetsController extends Controller
|
||||
{
|
||||
use MigratesLegacyAssetLocations;
|
||||
|
||||
/**
|
||||
* Returns JSON listing of all assets
|
||||
*
|
||||
@@ -88,6 +94,7 @@ class AssetsController extends Controller
|
||||
'serial',
|
||||
'model_number',
|
||||
'last_checkout',
|
||||
'last_checkin',
|
||||
'notes',
|
||||
'expected_checkin',
|
||||
'order_number',
|
||||
@@ -105,6 +112,7 @@ class AssetsController extends Controller
|
||||
'requests_counter',
|
||||
'byod',
|
||||
'asset_eol_date',
|
||||
'requestable',
|
||||
];
|
||||
|
||||
$filter = [];
|
||||
@@ -584,6 +592,11 @@ class AssetsController extends Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($field->element == 'checkbox') {
|
||||
if(is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
@@ -607,6 +620,8 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
@@ -652,13 +667,22 @@ class AssetsController extends Controller
|
||||
// Update custom fields
|
||||
if (($model) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
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));
|
||||
$asset->{$field->db_column} = Crypt::encrypt($field_val);
|
||||
}
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
if ($field->element == 'checkbox') {
|
||||
if(is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -686,6 +710,7 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
@@ -864,11 +889,9 @@ class AssetsController extends Controller
|
||||
*/
|
||||
public function checkin(Request $request, $asset_id)
|
||||
{
|
||||
$this->authorize('checkin', Asset::class);
|
||||
$asset = Asset::with('model')->findOrFail($asset_id);
|
||||
$this->authorize('checkin', $asset);
|
||||
|
||||
|
||||
$target = $asset->assignedTo;
|
||||
if (is_null($target)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||
@@ -879,9 +902,8 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$asset->expected_checkin = null;
|
||||
$asset->last_checkout = null;
|
||||
//$asset->last_checkout = null;
|
||||
$asset->last_checkin = now();
|
||||
$asset->assigned_to = null;
|
||||
$asset->assignedTo()->disassociate($asset);
|
||||
$asset->accepted = null;
|
||||
|
||||
@@ -889,10 +911,16 @@ class AssetsController extends Controller
|
||||
$asset->name = $request->input('name');
|
||||
}
|
||||
|
||||
$this->migrateLegacyLocations($asset);
|
||||
|
||||
$asset->location_id = $asset->rtd_location_id;
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$asset->location_id = $request->input('location_id');
|
||||
|
||||
if ($request->input('update_default_location')){
|
||||
$asset->rtd_location_id = $request->input('location_id');
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->has('status_id')) {
|
||||
@@ -906,6 +934,23 @@ class AssetsController extends Controller
|
||||
$originalValues['action_date'] = $checkin_at;
|
||||
}
|
||||
|
||||
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
||||
$seat->update(['assigned_to' => null]);
|
||||
});
|
||||
|
||||
// Get all pending Acceptances for this asset and delete them
|
||||
CheckoutAcceptance::pending()
|
||||
->whereHasMorph(
|
||||
'checkoutable',
|
||||
[Asset::class],
|
||||
function (Builder $query) use ($asset) {
|
||||
$query->where('id', $asset->id);
|
||||
})
|
||||
->get()
|
||||
->map(function ($acceptance) {
|
||||
$acceptance->delete();
|
||||
});
|
||||
|
||||
if ($asset->save()) {
|
||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
||||
|
||||
@@ -1035,8 +1080,7 @@ class AssetsController extends Controller
|
||||
|
||||
$assets = Asset::select('assets.*')
|
||||
->with('location', 'assetstatus', 'assetlog', 'company','assignedTo',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier', 'requests')
|
||||
->requestableAssets();
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier', 'requests');
|
||||
|
||||
|
||||
|
||||
@@ -1044,7 +1088,7 @@ class AssetsController extends Controller
|
||||
if ($request->filled('search')) {
|
||||
$assets->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
|
||||
// Search custom fields by column name
|
||||
foreach ($all_custom_fields as $field) {
|
||||
if ($request->filled($field->db_column_name())) {
|
||||
@@ -1074,6 +1118,7 @@ class AssetsController extends Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$assets->requestableAssets();
|
||||
|
||||
// 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');
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\GroupsTransformer;
|
||||
use App\Models\Group;
|
||||
use Illuminate\Http\Request;
|
||||
use Auth;
|
||||
|
||||
|
||||
class GroupsController extends Controller
|
||||
@@ -25,7 +26,7 @@ class GroupsController extends Controller
|
||||
$this->authorize('view', Group::class);
|
||||
$allowed_columns = ['id', 'name', 'created_at', 'users_count'];
|
||||
|
||||
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at')->withCount('users as users_count');
|
||||
$groups = Group::select('id', 'name', 'permissions', 'created_at', 'updated_at', 'created_by')->with('admin')->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$groups = $groups->TextSearch($request->input('search'));
|
||||
@@ -63,6 +64,7 @@ class GroupsController extends Controller
|
||||
$group = new Group;
|
||||
|
||||
$group->name = $request->input('name');
|
||||
$group->created_by = Auth::user()->id;
|
||||
$group->permissions = json_encode($request->input('permissions')); // Todo - some JSON validation stuff here
|
||||
|
||||
if ($group->save()) {
|
||||
|
||||
@@ -136,6 +136,7 @@ class LicensesController extends Controller
|
||||
'seats',
|
||||
'termination_date',
|
||||
'depreciation_id',
|
||||
'min_amt',
|
||||
];
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
$licenses = $licenses->orderBy($sort, $order);
|
||||
|
||||
@@ -25,9 +25,27 @@ class LocationsController extends Controller
|
||||
{
|
||||
$this->authorize('view', Location::class);
|
||||
$allowed_columns = [
|
||||
'id', 'name', 'address', 'address2', 'city', 'state', 'country', 'zip', 'created_at',
|
||||
'updated_at', 'manager_id', 'image',
|
||||
'assigned_assets_count', 'users_count', 'assets_count','assigned_assets_count', 'assets_count', 'rtd_assets_count', 'currency', 'ldap_ou', ];
|
||||
'id',
|
||||
'name',
|
||||
'address',
|
||||
'address2',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'zip',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'manager_id',
|
||||
'image',
|
||||
'assigned_assets_count',
|
||||
'users_count',
|
||||
'assets_count',
|
||||
'assigned_assets_count',
|
||||
'assets_count',
|
||||
'rtd_assets_count',
|
||||
'currency',
|
||||
'ldap_ou',
|
||||
];
|
||||
|
||||
$locations = Location::with('parent', 'manager', 'children')->select([
|
||||
'locations.id',
|
||||
@@ -50,6 +68,7 @@ class LocationsController extends Controller
|
||||
])->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('rtd_assets as rtd_assets_count')
|
||||
->withCount('children as children_count')
|
||||
->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
@@ -80,6 +99,10 @@ class LocationsController extends Controller
|
||||
$locations->where('locations.country', '=', $request->input('country'));
|
||||
}
|
||||
|
||||
if ($request->filled('manager_id')) {
|
||||
$locations->where('locations.manager_id', '=', $request->input('manager_id'));
|
||||
}
|
||||
|
||||
// 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');
|
||||
$limit = app('api_limit_value');
|
||||
@@ -212,7 +235,13 @@ class LocationsController extends Controller
|
||||
public function destroy($id)
|
||||
{
|
||||
$this->authorize('delete', Location::class);
|
||||
$location = Location::findOrFail($id);
|
||||
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('rtd_assets as rtd_assets_count')
|
||||
->withCount('children as children_count')
|
||||
->withCount('users as users_count')
|
||||
->findOrFail($id);
|
||||
|
||||
if (! $location->isDeletable()) {
|
||||
return response()
|
||||
->json(Helper::formatStandardApiResponse('error', null, trans('admin/companies/message.assoc_users')));
|
||||
|
||||
@@ -32,19 +32,26 @@ class ReportsController extends Controller
|
||||
}
|
||||
|
||||
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
|
||||
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
|
||||
$actionlogs = $actionlogs->where(function($query) use ($request)
|
||||
{
|
||||
$query->where('item_id', '=', $request->input('item_id'))
|
||||
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')))
|
||||
->orWhere(function($query) use ($request)
|
||||
{
|
||||
$query->where('target_id', '=', $request->input('item_id'))
|
||||
->where('target_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->filled('action_type')) {
|
||||
$actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
if ($request->filled('user_id')) {
|
||||
$actionlogs = $actionlogs->where('user_id', '=', $request->input('user_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('action_source')) {
|
||||
$actionlogs = $actionlogs->where('action_source', '=', $request->input('action_source'))->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ class SettingsController extends Controller
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @return Redirect
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function ajaxTestEmail()
|
||||
{
|
||||
@@ -170,7 +170,7 @@ class SettingsController extends Controller
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0.0]
|
||||
* @return Response
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function purgeBarcodes()
|
||||
{
|
||||
@@ -211,7 +211,7 @@ class SettingsController extends Controller
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0.0]
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
* @return array | JsonResponse
|
||||
*/
|
||||
public function showLoginAttempts(Request $request)
|
||||
{
|
||||
@@ -229,6 +229,12 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lists backup files
|
||||
*
|
||||
* @author [A. Gianotto]
|
||||
* @return array | JsonResponse
|
||||
*/
|
||||
public function listBackups() {
|
||||
$settings = Setting::getSettings();
|
||||
$path = 'app/backups';
|
||||
@@ -249,12 +255,12 @@ class SettingsController extends Controller
|
||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||
'modified_value' => $file_timestamp,
|
||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||
'backup_url' => config('app.url').'/settings/backups/download/'.basename($backup_files[$f]),
|
||||
|
||||
];
|
||||
$count++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,15 +270,56 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Downloads a backup file.
|
||||
* We use response()->download() here instead of Storage::download() because Storage::download()
|
||||
* exhausts memory on larger files.
|
||||
*
|
||||
* @author [A. Gianotto]
|
||||
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function downloadBackup($file) {
|
||||
|
||||
$path = 'app/backups';
|
||||
if (Storage::exists($path.'/'.$file)) {
|
||||
$path = storage_path('app/backups');
|
||||
|
||||
if (Storage::exists('app/backups/'.$file)) {
|
||||
$headers = ['ContentType' => 'application/zip'];
|
||||
return Storage::download($path.'/'.$file, $file, $headers);
|
||||
return response()->download($path.'/'.$file, $file, $headers);
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines and downloads the latest backup
|
||||
*
|
||||
* @author [A. Gianotto]
|
||||
* @since [v6.3.1]
|
||||
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function downloadLatestBackup() {
|
||||
|
||||
$fileData = collect();
|
||||
foreach (Storage::files('app/backups') as $file) {
|
||||
if (pathinfo($file, PATHINFO_EXTENSION) == 'zip') {
|
||||
$fileData->push([
|
||||
'file' => $file,
|
||||
'date' => Storage::lastModified($file)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$newest = $fileData->sortByDesc('date')->first();
|
||||
if (Storage::exists($newest['file'])) {
|
||||
$headers = ['ContentType' => 'application/zip'];
|
||||
return response()->download(storage_path($newest['file']), basename($newest['file']), $headers);
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -73,6 +73,7 @@ class UsersController extends Controller
|
||||
'users.end_date',
|
||||
'users.vip',
|
||||
'users.autoassign_licenses',
|
||||
'users.website',
|
||||
|
||||
])->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');
|
||||
@@ -122,6 +123,10 @@ class UsersController extends Controller
|
||||
$users = $users->where('users.country', '=', $request->input('country'));
|
||||
}
|
||||
|
||||
if ($request->filled('website')) {
|
||||
$users = $users->where('users.website', '=', $request->input('website'));
|
||||
}
|
||||
|
||||
if ($request->filled('zip')) {
|
||||
$users = $users->where('users.zip', '=', $request->input('zip'));
|
||||
}
|
||||
@@ -254,6 +259,7 @@ class UsersController extends Controller
|
||||
'start_date',
|
||||
'end_date',
|
||||
'autoassign_licenses',
|
||||
'website',
|
||||
];
|
||||
|
||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
||||
@@ -274,11 +280,6 @@ class UsersController extends Controller
|
||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
\Log::debug('Requested offset: '. $request->input('offset'));
|
||||
\Log::debug('App offset: '. app('api_offset_value'));
|
||||
\Log::debug('Actual offset: '. $offset);
|
||||
\Log::debug('Limit: '. $limit);
|
||||
|
||||
$total = $users->count();
|
||||
$users = $users->skip($offset)->take($limit)->get();
|
||||
|
||||
@@ -559,7 +560,26 @@ class UsersController extends Controller
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$this->authorize('view', Asset::class);
|
||||
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model')->get();
|
||||
$assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model');
|
||||
|
||||
|
||||
// Filter on category ID
|
||||
if ($request->filled('category_id')) {
|
||||
$assets = $assets->InCategory($request->input('category_id'));
|
||||
}
|
||||
|
||||
|
||||
// Filter on model ID
|
||||
if ($request->filled('model_id')) {
|
||||
|
||||
$model_ids = $request->input('model_id');
|
||||
if (!is_array($model_ids)) {
|
||||
$model_ids = array($model_ids);
|
||||
}
|
||||
$assets = $assets->InModelList($model_ids);
|
||||
}
|
||||
|
||||
$assets = $assets->get();
|
||||
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||
}
|
||||
@@ -660,7 +680,17 @@ class UsersController extends Controller
|
||||
$user = User::find($request->get('id'));
|
||||
$user->two_factor_secret = null;
|
||||
$user->two_factor_enrolled = 0;
|
||||
$user->save();
|
||||
$user->saveQuietly();
|
||||
|
||||
// Log the reset
|
||||
$logaction = new Actionlog();
|
||||
$logaction->target_type = User::class;
|
||||
$logaction->target_id = $user->id;
|
||||
$logaction->item_type = User::class;
|
||||
$logaction->item_id = $user->id;
|
||||
$logaction->created_at = date('Y-m-d H:i:s');
|
||||
$logaction->user_id = Auth::user()->id;
|
||||
$logaction->logaction('2FA reset');
|
||||
|
||||
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -442,7 +443,6 @@ class AssetModelsController extends Controller
|
||||
$del_count = 0;
|
||||
|
||||
foreach ($models as $model) {
|
||||
\Log::debug($model->id);
|
||||
|
||||
if ($model->assets_count > 0) {
|
||||
$del_error_count++;
|
||||
@@ -452,8 +452,6 @@ class AssetModelsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
\Log::debug($del_count);
|
||||
\Log::debug($del_error_count);
|
||||
|
||||
if ($del_error_count == 0) {
|
||||
return redirect()->route('models.index')
|
||||
@@ -489,11 +487,11 @@ class AssetModelsController extends Controller
|
||||
* @param array $defaultValues
|
||||
* @return void
|
||||
*/
|
||||
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues)
|
||||
private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues): bool
|
||||
{
|
||||
$data = array();
|
||||
foreach ($defaultValues as $customFieldId => $defaultValue) {
|
||||
$customField = \App\Models\CustomField::find($customFieldId);
|
||||
$customField = CustomField::find($customFieldId);
|
||||
|
||||
$data[$customField->db_column] = $defaultValue;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ use App\Events\CheckoutableCheckedIn;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetCheckinRequest;
|
||||
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
@@ -15,6 +17,8 @@ use Illuminate\Support\Facades\View;
|
||||
|
||||
class AssetCheckinController extends Controller
|
||||
{
|
||||
use MigratesLegacyAssetLocations;
|
||||
|
||||
/**
|
||||
* Returns a view that presents a form to check an asset back into inventory.
|
||||
*
|
||||
@@ -67,11 +71,9 @@ class AssetCheckinController extends Controller
|
||||
}
|
||||
|
||||
$asset->expected_checkin = null;
|
||||
$asset->last_checkout = null;
|
||||
//$asset->last_checkout = null;
|
||||
$asset->last_checkin = now();
|
||||
$asset->assigned_to = null;
|
||||
$asset->assignedTo()->disassociate($asset);
|
||||
$asset->assigned_type = null;
|
||||
$asset->accepted = null;
|
||||
$asset->name = $request->get('name');
|
||||
|
||||
@@ -79,24 +81,7 @@ class AssetCheckinController extends Controller
|
||||
$asset->status_id = e($request->get('status_id'));
|
||||
}
|
||||
|
||||
// This is just meant to correct legacy issues where some user data would have 0
|
||||
// as a location ID, which isn't valid. Later versions of Snipe-IT have stricter validation
|
||||
// rules, so it's necessary to fix this for long-time users. It's kinda gross, but will help
|
||||
// people (and their data) in the long run
|
||||
|
||||
if ($asset->rtd_location_id == '0') {
|
||||
\Log::debug('Manually override the RTD location IDs');
|
||||
\Log::debug('Original RTD Location ID: '.$asset->rtd_location_id);
|
||||
$asset->rtd_location_id = '';
|
||||
\Log::debug('New RTD Location ID: '.$asset->rtd_location_id);
|
||||
}
|
||||
|
||||
if ($asset->location_id == '0') {
|
||||
\Log::debug('Manually override the location IDs');
|
||||
\Log::debug('Original Location ID: '.$asset->location_id);
|
||||
$asset->location_id = '';
|
||||
\Log::debug('New Location ID: '.$asset->location_id);
|
||||
}
|
||||
$this->migrateLegacyLocations($asset);
|
||||
|
||||
$asset->location_id = $asset->rtd_location_id;
|
||||
|
||||
@@ -117,12 +102,9 @@ class AssetCheckinController extends Controller
|
||||
$checkin_at = $request->get('checkin_at');
|
||||
}
|
||||
|
||||
if(!empty($asset->licenseseats->all())){
|
||||
foreach ($asset->licenseseats as $seat){
|
||||
$seat->assigned_to = null;
|
||||
$seat->save();
|
||||
}
|
||||
}
|
||||
$asset->licenseseats->each(function (LicenseSeat $seat) {
|
||||
$seat->update(['assigned_to' => null]);
|
||||
});
|
||||
|
||||
// Get all pending Acceptances for this asset and delete them
|
||||
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
|
||||
|
||||
@@ -102,6 +102,10 @@ class AssetsController extends Controller
|
||||
{
|
||||
$this->authorize(Asset::class);
|
||||
|
||||
// There are a lot more rules to add here but prevents
|
||||
// errors around `asset_tags` not being present below.
|
||||
$this->validate($request, ['asset_tags' => ['required', 'array']]);
|
||||
|
||||
// Handle asset tags - there could be one, or potentially many.
|
||||
// This is only necessary on create, not update, since bulk editing is handled
|
||||
// differently
|
||||
@@ -737,11 +741,11 @@ class AssetsController extends Controller
|
||||
|
||||
if ($isCheckinHeaderExplicit) {
|
||||
|
||||
//if checkin date header exists, assume that empty or future date is still checked out
|
||||
//if checkin is before todays date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items is checked out
|
||||
// if checkin date header exists, assume that empty or future date is still checked out
|
||||
// if checkin is before today's date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items are checked out
|
||||
|
||||
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date))
|
||||
) {
|
||||
if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date)))
|
||||
{
|
||||
//only do this if item is checked out
|
||||
$asset->assigned_to = $user->id;
|
||||
$asset->assigned_type = User::class;
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\View\Label;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\Http\Requests\AssetCheckoutRequest;
|
||||
use App\Models\CustomField;
|
||||
@@ -93,6 +94,59 @@ class BulkAssetsController extends Controller
|
||||
|
||||
$assets = Asset::with('assignedTo', 'location', 'model')->whereIn('assets.id', $asset_ids);
|
||||
|
||||
$assets = $assets->get();
|
||||
|
||||
if ($assets->isEmpty()) {
|
||||
Log::debug('No assets were found for the provided IDs', ['ids' => $asset_ids]);
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.update.assets_do_not_exist_or_are_invalid'));
|
||||
}
|
||||
|
||||
$models = $assets->unique('model_id');
|
||||
$modelNames = [];
|
||||
foreach($models as $model) {
|
||||
$modelNames[] = $model->model->name;
|
||||
}
|
||||
|
||||
if ($request->filled('bulk_actions')) {
|
||||
|
||||
|
||||
switch ($request->input('bulk_actions')) {
|
||||
case 'labels':
|
||||
$this->authorize('view', Asset::class);
|
||||
|
||||
return (new Label)
|
||||
->with('assets', $assets)
|
||||
->with('settings', Setting::getSettings())
|
||||
->with('bulkedit', true)
|
||||
->with('count', 0);
|
||||
|
||||
case 'delete':
|
||||
$this->authorize('delete', Asset::class);
|
||||
$assets->each(function ($assets) {
|
||||
$this->authorize('delete', $assets);
|
||||
});
|
||||
|
||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||
|
||||
case 'restore':
|
||||
$this->authorize('update', Asset::class);
|
||||
$assets = Asset::withTrashed()->find($asset_ids);
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('delete', $asset);
|
||||
});
|
||||
return view('hardware/bulk-restore')->with('assets', $assets);
|
||||
|
||||
case 'edit':
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
return view('hardware/bulk')
|
||||
->with('assets', $asset_ids)
|
||||
->with('statuslabel_list', Helper::statusLabelList())
|
||||
->with('models', $models->pluck(['model']))
|
||||
->with('modelNames', $modelNames);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($sort_override) {
|
||||
case 'model':
|
||||
$assets->OrderModels($order);
|
||||
@@ -128,54 +182,6 @@ class BulkAssetsController extends Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$assets = $assets->get();
|
||||
|
||||
$models = $assets->unique('model_id');
|
||||
$modelNames = [];
|
||||
foreach($models as $model) {
|
||||
$modelNames[] = $model->model->name;
|
||||
}
|
||||
|
||||
if ($request->filled('bulk_actions')) {
|
||||
|
||||
|
||||
switch ($request->input('bulk_actions')) {
|
||||
case 'labels':
|
||||
$this->authorize('view', Asset::class);
|
||||
|
||||
return (new Label)
|
||||
->with('assets', $assets)
|
||||
->with('settings', Setting::getSettings())
|
||||
->with('bulkedit', true)
|
||||
->with('count', 0);
|
||||
|
||||
case 'delete':
|
||||
$this->authorize('delete', Asset::class);
|
||||
$assets->each(function ($assets) {
|
||||
$this->authorize('delete', $assets);
|
||||
});
|
||||
|
||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||
|
||||
case 'restore':
|
||||
$this->authorize('update', Asset::class);
|
||||
$assets = Asset::withTrashed()->find($asset_ids);
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('delete', $asset);
|
||||
});
|
||||
return view('hardware/bulk-restore')->with('assets', $assets);
|
||||
|
||||
case 'edit':
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
return view('hardware/bulk')
|
||||
->with('assets', $asset_ids)
|
||||
->with('statuslabel_list', Helper::statusLabelList())
|
||||
->with('models', $models->pluck(['model']))
|
||||
->with('modelNames', $modelNames);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', 'No action selected');
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ class CustomFieldsController extends Controller
|
||||
|
||||
$field->name = trim(e($request->get("name")));
|
||||
$field->element = e($request->get("element"));
|
||||
$field->field_values = e($request->get("field_values"));
|
||||
$field->field_values = $request->get("field_values");
|
||||
$field->user_id = Auth::id();
|
||||
$field->help_text = $request->get("help_text");
|
||||
$field->show_in_email = $show_in_email;
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Group;
|
||||
use Illuminate\Http\Request;
|
||||
use Auth;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to User Groups for
|
||||
@@ -63,6 +64,7 @@ class GroupsController extends Controller
|
||||
$group = new Group();
|
||||
$group->name = $request->input('name');
|
||||
$group->permissions = json_encode($request->input('permission'));
|
||||
$group->created_by = Auth::user()->id;
|
||||
|
||||
if ($group->save()) {
|
||||
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Labels\Label;
|
||||
use App\Models\Location;
|
||||
use App\Models\Manufacturer;
|
||||
@@ -65,6 +66,20 @@ class LabelsController extends Controller
|
||||
$exampleAsset->model->category->id = 999999;
|
||||
$exampleAsset->model->category->name = trans('admin/labels/table.example_category');
|
||||
|
||||
$customFieldColumns = CustomField::all()->pluck('db_column');
|
||||
|
||||
collect(explode(';', Setting::getSettings()->label2_fields))
|
||||
->filter()
|
||||
->each(function ($item) use ($customFieldColumns, $exampleAsset) {
|
||||
$pair = explode('=', $item);
|
||||
|
||||
if (array_key_exists(1, $pair)) {
|
||||
if ($customFieldColumns->contains($pair[1])) {
|
||||
$exampleAsset->{$pair[1]} = "{{$pair[0]}}";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
if (request()->has('settings')) {
|
||||
$overrides = request()->get('settings');
|
||||
|
||||
@@ -99,6 +99,7 @@ class LicensesController extends Controller
|
||||
$license->category_id = $request->input('category_id');
|
||||
$license->termination_date = $request->input('termination_date');
|
||||
$license->user_id = Auth::id();
|
||||
$license->min_amt = $request->input('min_amt');
|
||||
|
||||
if ($license->save()) {
|
||||
return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.create.success'));
|
||||
@@ -176,6 +177,7 @@ class LicensesController extends Controller
|
||||
$license->manufacturer_id = $request->input('manufacturer_id');
|
||||
$license->supplier_id = $request->input('supplier_id');
|
||||
$license->category_id = $request->input('category_id');
|
||||
$license->min_amt = $request->input('min_amt');
|
||||
|
||||
if ($license->save()) {
|
||||
return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success'));
|
||||
@@ -245,12 +247,6 @@ class LicensesController extends Controller
|
||||
$available_seats_count = $license->availCount()->count();
|
||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
||||
|
||||
\Log::debug('Total: '.$total_seats_count);
|
||||
\Log::debug('Users: '.$users_count);
|
||||
\Log::debug('Available: '.$available_seats_count);
|
||||
\Log::debug('Checkedout: '.$checkedout_seats_count);
|
||||
|
||||
|
||||
$this->authorize('view', $license);
|
||||
return view('licenses.view', compact('license'))
|
||||
->with('users_count', $users_count)
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Locations for
|
||||
@@ -238,7 +239,7 @@ class LocationsController extends Controller
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $locationId
|
||||
* @since [v6.0.14]
|
||||
* @return View
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function getClone($locationId = null)
|
||||
{
|
||||
@@ -272,8 +273,102 @@ class LocationsController extends Controller
|
||||
|
||||
}
|
||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a view that allows the user to bulk delete locations
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.3.1]
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function postBulkDelete(Request $request)
|
||||
{
|
||||
$locations_raw_array = $request->input('ids');
|
||||
|
||||
// Make sure some IDs have been selected
|
||||
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
|
||||
$locations = Location::whereIn('id', $locations_raw_array)
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('rtd_assets as rtd_assets_count')
|
||||
->withCount('children as children_count')
|
||||
->withCount('users as users_count')->get();
|
||||
|
||||
$valid_count = 0;
|
||||
foreach ($locations as $location) {
|
||||
if ($location->isDeletable()) {
|
||||
$valid_count++;
|
||||
}
|
||||
}
|
||||
return view('locations/bulk-delete', compact('locations'))->with('valid_count', $valid_count);
|
||||
}
|
||||
|
||||
return redirect()->route('models.index')
|
||||
->with('error', 'You must select at least one model to edit.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that locations can be deleted and deletes them if they can
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.3.1]
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postBulkDeleteStore(Request $request) {
|
||||
$locations_raw_array = $request->input('ids');
|
||||
|
||||
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
|
||||
$locations = Location::whereIn('id', $locations_raw_array)
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('rtd_assets as rtd_assets_count')
|
||||
->withCount('children as children_count')
|
||||
->withCount('users as users_count')->get();
|
||||
|
||||
$success_count = 0;
|
||||
$error_count = 0;
|
||||
|
||||
foreach ($locations as $location) {
|
||||
|
||||
// Can we delete this location?
|
||||
if ($location->isDeletable()) {
|
||||
$location->delete();
|
||||
$success_count++;
|
||||
} else {
|
||||
$error_count++;
|
||||
}
|
||||
}
|
||||
|
||||
\Log::debug('Success count: '.$success_count);
|
||||
\Log::debug('Error count: '.$error_count);
|
||||
// Complete success
|
||||
if ($success_count == count($locations_raw_array)) {
|
||||
return redirect()
|
||||
->route('locations.index')
|
||||
->with('success', trans_choice('general.bulk.delete.success', $success_count,
|
||||
['object_type' => trans_choice('general.location_plural', $success_count), 'count' => $success_count]
|
||||
));
|
||||
}
|
||||
|
||||
// Partial success
|
||||
if ($error_count > 0) {
|
||||
return redirect()
|
||||
->route('locations.index')
|
||||
->with('warning', trans('general.bulk.delete.partial',
|
||||
['success' => $success_count, 'error' => $error_count, 'object_type' => trans('general.locations')]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Nothing was selected - return to the index
|
||||
return redirect()
|
||||
->route('locations.index')
|
||||
->with('error', trans('general.bulk.nothing_selected',
|
||||
['object_type' => trans('general.locations')]
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,8 +296,8 @@ class ReportsController extends Controller
|
||||
e($actionlog->itemType()),
|
||||
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
||||
($actionlog->item) ? $actionlog->item->serial : null,
|
||||
($actionlog->item->model) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
|
||||
($actionlog->item->model) ? $actionlog->item->model->model_number : null,
|
||||
(($actionlog->item) && ($actionlog->item->model)) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
|
||||
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
|
||||
$target_name,
|
||||
($actionlog->note) ? e($actionlog->note) : '',
|
||||
$actionlog->log_meta,
|
||||
@@ -686,20 +686,27 @@ class ReportsController extends Controller
|
||||
|
||||
$assets->whereBetween('assets.created_at', [$created_start, $created_end]);
|
||||
}
|
||||
|
||||
if (($request->filled('checkout_date_start')) && ($request->filled('checkout_date_end'))) {
|
||||
$checkout_start = \Carbon::parse($request->input('checkout_date_start'))->startOfDay();
|
||||
$checkout_end = \Carbon::parse($request->input('checkout_date_end'))->endOfDay();
|
||||
$checkout_end = \Carbon::parse($request->input('checkout_date_end',now()))->endOfDay();
|
||||
|
||||
$assets->whereBetween('assets.last_checkout', [$checkout_start, $checkout_end]);
|
||||
$actionlogassets = Actionlog::where('action_type','=', 'checkout')
|
||||
->where('item_type', 'LIKE', '%Asset%',)
|
||||
->whereBetween('action_date',[$checkout_start, $checkout_end])
|
||||
->pluck('item_id');
|
||||
|
||||
$assets->whereIn('id',$actionlogassets);
|
||||
}
|
||||
|
||||
if (($request->filled('checkin_date_start'))) {
|
||||
$assets->whereBetween('last_checkin', [
|
||||
Carbon::parse($request->input('checkin_date_start'))->startOfDay(),
|
||||
$checkin_start = \Carbon::parse($request->input('checkin_date_start'))->startOfDay();
|
||||
// use today's date is `checkin_date_end` is not provided
|
||||
Carbon::parse($request->input('checkin_date_end', now()))->endOfDay(),
|
||||
]);
|
||||
$checkin_end = \Carbon::parse($request->input('checkin_date_end', now()))->endOfDay();
|
||||
|
||||
$assets->whereBetween('assets.last_checkin', [$checkin_start, $checkin_end ]);
|
||||
}
|
||||
//last checkin is exporting, but currently is a date and not a datetime in the custom report ONLY.
|
||||
|
||||
if (($request->filled('expected_checkin_start')) && ($request->filled('expected_checkin_end'))) {
|
||||
$assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]);
|
||||
@@ -1156,16 +1163,24 @@ class ReportsController extends Controller
|
||||
$logItem = $logItem_res[0];
|
||||
}
|
||||
|
||||
if (!$assetItem->assignedTo->locale){
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$assetItem->assignedTo,
|
||||
new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)
|
||||
);
|
||||
} else {
|
||||
Notification::send(
|
||||
$assetItem->assignedTo,
|
||||
new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)
|
||||
);
|
||||
// Only send notification if assigned
|
||||
if ($assetItem->assignedTo) {
|
||||
|
||||
if (!$assetItem->assignedTo->locale) {
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$assetItem->assignedTo,
|
||||
new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)
|
||||
);
|
||||
} else {
|
||||
Notification::send(
|
||||
$assetItem->assignedTo,
|
||||
new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($assetItem->assignedTo->email == ''){
|
||||
return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.no_email'));
|
||||
}
|
||||
|
||||
return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent'));
|
||||
|
||||
@@ -20,6 +20,7 @@ use DB;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Image;
|
||||
use Input;
|
||||
use Redirect;
|
||||
@@ -422,68 +423,46 @@ class SettingsController extends Controller
|
||||
|
||||
// Only allow the site name and CSS to be changed if lock_passwords is false
|
||||
// Because public demos make people act like dicks
|
||||
|
||||
if (! config('app.lock_passwords')) {
|
||||
$setting->site_name = $request->input('site_name');
|
||||
$setting->custom_css = $request->input('custom_css');
|
||||
}
|
||||
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
||||
|
||||
if ('1' == $request->input('clear_logo')) {
|
||||
if ('1' == $request->input('clear_logo')) {
|
||||
Storage::disk('public')->delete($setting->logo);
|
||||
$setting->logo = null;
|
||||
$setting->logo = null;
|
||||
$setting->brand = 1;
|
||||
}
|
||||
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
|
||||
|
||||
|
||||
if ('1' == $request->input('clear_email_logo')) {
|
||||
Storage::disk('public')->delete($setting->email_logo);
|
||||
$setting->email_logo = null;
|
||||
// If they are uploading an image, validate it and upload it
|
||||
}
|
||||
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
||||
|
||||
|
||||
if ('1' == $request->input('clear_label_logo')) {
|
||||
Storage::disk('public')->delete($setting->label_logo);
|
||||
$setting->label_logo = null;
|
||||
}
|
||||
|
||||
|
||||
// If the user wants to clear the favicon...
|
||||
if ($request->hasFile('favicon')) {
|
||||
$favicon_image = $favicon_upload = $request->file('favicon');
|
||||
$favicon_ext = $favicon_image->getClientOriginalExtension();
|
||||
$setting->favicon = $favicon_file_name = 'favicon-uploaded.'.$favicon_ext;
|
||||
|
||||
if (($favicon_image->getClientOriginalExtension() != 'ico') && ($favicon_image->getClientOriginalExtension() != 'svg')) {
|
||||
$favicon_upload = Image::make($favicon_image->getRealPath())->resize(null, 36, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize();
|
||||
});
|
||||
|
||||
// This requires a string instead of an object, so we use ($string)
|
||||
Storage::disk('public')->put($favicon_file_name, (string) $favicon_upload->encode());
|
||||
} else {
|
||||
Storage::disk('public')->put($favicon_file_name, file_get_contents($request->file('favicon')));
|
||||
}
|
||||
|
||||
|
||||
// Remove Current image if exists
|
||||
if (($setting->favicon) && (file_exists($favicon_file_name))) {
|
||||
Storage::disk('public')->delete($favicon_file_name);
|
||||
}
|
||||
} elseif ('1' == $request->input('clear_favicon')) {
|
||||
Storage::disk('public')->delete($setting->clear_favicon);
|
||||
$setting->favicon = null;
|
||||
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
|
||||
|
||||
// If they are uploading an image, validate it and upload it
|
||||
}
|
||||
|
||||
if ('1' == $request->input('clear_email_logo')) {
|
||||
Storage::disk('public')->delete($setting->email_logo);
|
||||
$setting->email_logo = null;
|
||||
// If they are uploading an image, validate it and upload it
|
||||
}
|
||||
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
||||
|
||||
if ('1' == $request->input('clear_label_logo')) {
|
||||
Storage::disk('public')->delete($setting->label_logo);
|
||||
$setting->label_logo = null;
|
||||
}
|
||||
|
||||
|
||||
$setting = $request->handleImages($setting, 600, 'favicon', '', 'favicon');
|
||||
|
||||
// If the user wants to clear the favicon...
|
||||
if ('1' == $request->input('clear_favicon')) {
|
||||
Storage::disk('public')->delete($setting->favicon);
|
||||
$setting->favicon = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
@@ -521,6 +500,19 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function postSecurity(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'pwd_secure_complexity' => 'array',
|
||||
'pwd_secure_complexity.*' => [
|
||||
Rule::in([
|
||||
'disallow_same_pwd_as_user_fields',
|
||||
'letters',
|
||||
'numbers',
|
||||
'symbols',
|
||||
'case_diff',
|
||||
])
|
||||
]
|
||||
]);
|
||||
|
||||
if (is_null($setting = Setting::getSettings())) {
|
||||
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
|
||||
}
|
||||
|
||||
@@ -59,12 +59,21 @@ class Importer extends Component
|
||||
'field_map' => 'array'
|
||||
];
|
||||
|
||||
/**
|
||||
* This is used in resources/views/livewire/importer.blade.php, and we kinda shouldn't need to check for
|
||||
* activeFile here, but there's some UI goofiness that allows this to crash out on some imports.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_field_map()
|
||||
{
|
||||
\Log::debug("header row is: ".print_r($this->activeFile->header_row,true));
|
||||
\Log::debug("Field map is: ".print_r($this->field_map,true));
|
||||
$tmp = array_combine($this->activeFile->header_row, $this->field_map);
|
||||
return json_encode(array_filter($tmp));
|
||||
$tmp = array();
|
||||
if ($this->activeFile) {
|
||||
$tmp = array_combine($this->activeFile->header_row, $this->field_map);
|
||||
$tmp = array_filter($tmp);
|
||||
}
|
||||
return json_encode($tmp);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@ class SlackSettingsForm extends Component
|
||||
'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= [
|
||||
|
||||
@@ -8,6 +8,12 @@ use \App\Helpers\Helper;
|
||||
|
||||
class CheckLocale
|
||||
{
|
||||
private function warn_legacy_locale($language, $source)
|
||||
{
|
||||
if ($language != Helper::mapLegacyLocale($language)) {
|
||||
\Log::warning("$source $language and should be updated to be ".Helper::mapLegacyLocale($language));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handle the locale for the user, default to settings otherwise.
|
||||
*
|
||||
@@ -22,24 +28,23 @@ class CheckLocale
|
||||
|
||||
// Default app settings from config
|
||||
$language = config('app.locale');
|
||||
$this->warn_legacy_locale($language, "APP_LOCALE in .env is set to");
|
||||
|
||||
if ($settings = Setting::getSettings()) {
|
||||
|
||||
// User's preference
|
||||
if (($request->user()) && ($request->user()->locale)) {
|
||||
$language = $request->user()->locale;
|
||||
$this->warn_legacy_locale($language, "username ".$request->user()->username." (".$request->user()->id.") has a language");
|
||||
|
||||
// App setting preference
|
||||
} elseif ($settings->locale != '') {
|
||||
$language = $settings->locale;
|
||||
$this->warn_legacy_locale($language, "App Settings is set to");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (config('app.locale') != Helper::mapLegacyLocale($language)) {
|
||||
\Log::warning('Your current APP_LOCALE in your .env is set to "'.config('app.locale').'" and should be updated to be "'.Helper::mapLegacyLocale($language).'" in '.base_path().'/.env. Translations may display unexpectedly until this is updated.');
|
||||
}
|
||||
|
||||
|
||||
\App::setLocale(Helper::mapLegacyLocale($language));
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ class ImageUploadRequest extends Request
|
||||
{
|
||||
|
||||
return [
|
||||
'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp',
|
||||
'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp',
|
||||
'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp,avif',
|
||||
'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml,webp,avif',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -97,21 +97,19 @@ class ImageUploadRequest extends Request
|
||||
|
||||
if (!config('app.lock_passwords')) {
|
||||
|
||||
$ext = $image->getClientOriginalExtension();
|
||||
$ext = $image->guessExtension();
|
||||
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
|
||||
|
||||
\Log::info('File name will be: '.$file_name);
|
||||
\Log::debug('File extension is: '.$ext);
|
||||
|
||||
if ($image->getMimeType() == 'image/webp') {
|
||||
// If the file is a webp, we need to just move it since webp support
|
||||
if (($image->getMimeType() == 'image/avif') || ($image->getMimeType() == 'image/webp')) {
|
||||
// If the file is a webp or avif, we need to just move it since webp support
|
||||
// needs to be compiled into gd for resizing to be available
|
||||
|
||||
\Log::debug('This is a webp, just move it');
|
||||
Storage::disk('public')->put($path.'/'.$file_name, file_get_contents($image));
|
||||
|
||||
} elseif($image->getMimeType() == 'image/svg+xml') {
|
||||
// If the file is an SVG, we need to clean it and NOT encode it
|
||||
\Log::debug('This is an SVG');
|
||||
$sanitizer = new Sanitizer();
|
||||
$dirtySVG = file_get_contents($image->getRealPath());
|
||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||
@@ -123,9 +121,6 @@ class ImageUploadRequest extends Request
|
||||
}
|
||||
} else {
|
||||
|
||||
\Log::debug('Not an SVG or webp - resize');
|
||||
\Log::debug('Trying to upload to: '.$path.'/'.$file_name);
|
||||
|
||||
try {
|
||||
$upload = Image::make($image->getRealPath())->setFileInfoFromPath($image->getRealPath())->resize(null, $w, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
@@ -147,10 +142,8 @@ class ImageUploadRequest extends Request
|
||||
|
||||
// Remove Current image if exists
|
||||
if (($item->{$form_fieldname}!='') && (Storage::disk('public')->exists($path.'/'.$item->{$db_fieldname}))) {
|
||||
\Log::debug('A file already exists that we are replacing - we should delete the old one.');
|
||||
try {
|
||||
Storage::disk('public')->delete($path.'/'.$item->{$form_fieldname});
|
||||
\Log::debug('Old file '.$path.'/'.$file_name.' has been deleted.');
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Could not delete old file. '.$path.'/'.$file_name.' does not exist?');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreAssetRequest extends ImageUploadRequest
|
||||
@@ -27,6 +29,8 @@ class StoreAssetRequest extends ImageUploadRequest
|
||||
? Company::getIdForCurrentUser($this->company_id)
|
||||
: $this->company_id;
|
||||
|
||||
$this->parseLastAuditDate();
|
||||
|
||||
$this->merge([
|
||||
'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(),
|
||||
'company_id' => $idForCurrentUser,
|
||||
@@ -48,4 +52,21 @@ class StoreAssetRequest extends ImageUploadRequest
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function parseLastAuditDate(): void
|
||||
{
|
||||
if ($this->input('last_audit_date')) {
|
||||
try {
|
||||
$lastAuditDate = Carbon::parse($this->input('last_audit_date'));
|
||||
|
||||
$this->merge([
|
||||
'last_audit_date' => $lastAuditDate->startOfDay()->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
} catch (InvalidFormatException $e) {
|
||||
// we don't need to do anything here...
|
||||
// we'll keep the provided date in an
|
||||
// invalid format so validation picks it up later
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class UploadFileRequest extends Request
|
||||
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
|
||||
|
||||
return [
|
||||
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp|max:'.$max_file_size,
|
||||
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp,avif|max:'.$max_file_size,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Traits;
|
||||
|
||||
use App\Models\Asset;
|
||||
|
||||
trait MigratesLegacyAssetLocations
|
||||
{
|
||||
/**
|
||||
* This is just meant to correct legacy issues where some user data would have 0
|
||||
* as a location ID, which isn't valid. Later versions of Snipe-IT have stricter validation
|
||||
* rules, so it's necessary to fix this for long-time users. It's kinda gross, but will help
|
||||
* people (and their data) in the long run
|
||||
* @param Asset $asset
|
||||
* @return void
|
||||
*/
|
||||
private function migrateLegacyLocations(Asset $asset): void
|
||||
{
|
||||
if ($asset->rtd_location_id == '0') {
|
||||
\Log::debug('Manually override the RTD location IDs');
|
||||
\Log::debug('Original RTD Location ID: ' . $asset->rtd_location_id);
|
||||
$asset->rtd_location_id = '';
|
||||
\Log::debug('New RTD Location ID: ' . $asset->rtd_location_id);
|
||||
}
|
||||
|
||||
if ($asset->location_id == '0') {
|
||||
\Log::debug('Manually override the location IDs');
|
||||
\Log::debug('Original Location ID: ' . $asset->location_id);
|
||||
$asset->location_id = '';
|
||||
\Log::debug('New Location ID: ' . $asset->location_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ class AssetsTransformer
|
||||
'name'=> e($asset->model->name),
|
||||
] : null,
|
||||
'byod' => ($asset->byod ? true : false),
|
||||
'requestable' => ($asset->requestable ? true : false),
|
||||
|
||||
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
|
||||
'eol' => (($asset->asset_eol_date != '') && ($asset->purchase_date != '')) ? Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date).' months' : null,
|
||||
@@ -87,6 +88,7 @@ class AssetsTransformer
|
||||
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
|
||||
'age' => $asset->purchase_date ? $asset->purchase_date->diffForHumans() : '',
|
||||
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
|
||||
'last_checkin' => Helper::getFormattedDateObject($asset->last_checkin, 'datetime'),
|
||||
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
|
||||
'checkin_counter' => (int) $asset->checkin_counter,
|
||||
|
||||
@@ -26,6 +26,7 @@ class GroupsTransformer
|
||||
'name' => e($group->name),
|
||||
'permissions' => json_decode($group->permissions),
|
||||
'users_count' => (int) $group->users_count,
|
||||
'created_by' => ($group->admin) ? e($group->admin->present()->fullName) : null,
|
||||
'created_at' => Helper::getFormattedDateObject($group->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($group->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -27,8 +27,8 @@ class LicensesTransformer
|
||||
'company' => ($license->company) ? ['id' => (int) $license->company->id, 'name'=> e($license->company->name)] : null,
|
||||
'manufacturer' => ($license->manufacturer) ? ['id' => (int) $license->manufacturer->id, 'name'=> e($license->manufacturer->name)] : null,
|
||||
'product_key' => (Gate::allows('viewKeys', License::class)) ? e($license->serial) : '------------',
|
||||
'order_number' => e($license->order_number),
|
||||
'purchase_order' => e($license->purchase_order),
|
||||
'order_number' => ($license->order_number) ? e($license->order_number) : null,
|
||||
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
|
||||
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
|
||||
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
|
||||
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
|
||||
@@ -38,8 +38,9 @@ class LicensesTransformer
|
||||
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
|
||||
'seats' => (int) $license->seats,
|
||||
'free_seats_count' => (int) $license->free_seats_count,
|
||||
'license_name' => e($license->license_name),
|
||||
'license_email' => e($license->license_email),
|
||||
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
|
||||
'license_name' => ($license->license_name) ? e($license->license_name) : null,
|
||||
'license_email' => ($license->license_email) ? e($license->license_email) : null,
|
||||
'reassignable' => ($license->reassignable == 1) ? true : false,
|
||||
'maintained' => ($license->maintained == 1) ? true : false,
|
||||
'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id, 'name'=> e($license->supplier->name)] : null,
|
||||
|
||||
@@ -65,6 +65,9 @@ class LocationsTransformer
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => Gate::allows('update', Location::class) ? true : false,
|
||||
'delete' => $location->isDeletable(),
|
||||
'bulk_selectable' => [
|
||||
'delete' => $location->isDeletable()
|
||||
],
|
||||
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
||||
];
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ class Accessory extends SnipeModel
|
||||
*/
|
||||
public function requireAcceptance()
|
||||
{
|
||||
return $this->category->require_acceptance;
|
||||
return $this->category->require_acceptance ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,10 @@ class Asset extends Depreciable
|
||||
'company_id' => 'nullable|integer|exists:companies,id',
|
||||
'warranty_months' => 'nullable|numeric|digits_between:0,240',
|
||||
'last_checkout' => 'nullable|date_format:Y-m-d H:i:s',
|
||||
'last_checkin' => 'nullable|date_format:Y-m-d H:i:s',
|
||||
'expected_checkin' => 'nullable|date',
|
||||
'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s',
|
||||
'next_audit_date' => 'nullable|date|after:last_audit_date',
|
||||
'location_id' => 'nullable|exists:locations,id',
|
||||
'rtd_location_id' => 'nullable|exists:locations,id',
|
||||
'purchase_date' => 'nullable|date|date_format:Y-m-d',
|
||||
@@ -167,6 +170,8 @@ class Asset extends Depreciable
|
||||
'expected_checkin',
|
||||
'next_audit_date',
|
||||
'last_audit_date',
|
||||
'last_checkin',
|
||||
'last_checkout',
|
||||
'asset_eol_date',
|
||||
];
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace App\Models;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class CustomFieldset extends Model
|
||||
@@ -92,8 +94,19 @@ class CustomFieldset extends Model
|
||||
|
||||
array_push($rule, $field->attributes['format']);
|
||||
$rules[$field->db_column_name()] = $rule;
|
||||
//add not_array to rules for all fields
|
||||
$rules[$field->db_column_name()][] = 'not_array';
|
||||
|
||||
// add not_array to rules for all fields but checkboxes
|
||||
if ($field->element != 'checkbox') {
|
||||
$rules[$field->db_column_name()][] = 'not_array';
|
||||
}
|
||||
|
||||
if ($field->element == 'checkbox') {
|
||||
$rules[$field->db_column_name()][] = 'checkboxes';
|
||||
}
|
||||
|
||||
if ($field->element == 'radio') {
|
||||
$rules[$field->db_column_name()][] = 'radio_buttons';
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
||||
@@ -58,6 +58,18 @@ class Group extends SnipeModel
|
||||
return $this->belongsToMany(\App\Models\User::class, 'users_groups');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that created the group
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function admin()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\User::class, 'created_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode JSON permissions into array
|
||||
*
|
||||
|
||||
@@ -160,75 +160,27 @@ class DefaultLabel extends RectangleSheet
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
}
|
||||
|
||||
// Fields
|
||||
// Render the selected fields with their labels
|
||||
$fieldsDone = 0;
|
||||
if ($settings->labels_display_name && $fieldsDone < $this->getSupportFields()) {
|
||||
if ($asset->name) {
|
||||
static::writeText(
|
||||
$pdf, 'N: '.$asset->name,
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
if ($settings->labels_display_company_name && $fieldsDone < $this->getSupportFields()) {
|
||||
if ($asset->company) {
|
||||
static::writeText(
|
||||
$pdf, 'C: '.$asset->company->name,
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
if ($settings->labels_display_tag && $fieldsDone < $this->getSupportFields()) {
|
||||
if ($asset->asset_tag) {
|
||||
static::writeText(
|
||||
$pdf, 'T: '.$asset->asset_tag,
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
if ($settings->labels_display_serial && $fieldsDone < $this->getSupportFields()) {
|
||||
if ($asset->serial) {
|
||||
static::writeText(
|
||||
$pdf, 'S: '.$asset->serial,
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
if ($settings->labels_display_model && $fieldsDone < $this->getSupportFields()) {
|
||||
if ($asset->model) {
|
||||
static::writeText(
|
||||
$pdf, 'M: '.$asset->model->name,
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
if ($fieldsDone < $this->getSupportFields()) {
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
|
||||
// Actually write the selected fields and their matching values
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Labels\Tapes\Dymo;
|
||||
|
||||
|
||||
class LabelWriter_1933081 extends LabelWriter
|
||||
{
|
||||
private const BARCODE_MARGIN = 1.80;
|
||||
private const TAG_SIZE = 2.80;
|
||||
private const TITLE_SIZE = 2.80;
|
||||
private const TITLE_MARGIN = 0.50;
|
||||
private const LABEL_SIZE = 2.80;
|
||||
private const LABEL_MARGIN = - 0.35;
|
||||
private const FIELD_SIZE = 2.80;
|
||||
private const FIELD_MARGIN = 0.15;
|
||||
|
||||
public function getUnit() { return 'mm'; }
|
||||
public function getWidth() { return 89; }
|
||||
public function getHeight() { return 25; }
|
||||
public function getSupportAssetTag() { return true; }
|
||||
public function getSupport1DBarcode() { return true; }
|
||||
public function getSupport2DBarcode() { return true; }
|
||||
public function getSupportFields() { return 5; }
|
||||
public function getSupportLogo() { return false; }
|
||||
public function getSupportTitle() { return true; }
|
||||
|
||||
public function preparePDF($pdf) {}
|
||||
|
||||
public function write($pdf, $record) {
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$usableWidth = $pa->w;
|
||||
|
||||
$barcodeSize = $pa->h - self::TAG_SIZE;
|
||||
|
||||
if ($record->has('barcode2d')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE,
|
||||
'freesans', 'b', self::TAG_SIZE, 'C',
|
||||
$barcodeSize, self::TAG_SIZE, true, 0
|
||||
);
|
||||
static::write2DBarcode(
|
||||
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
|
||||
$currentX, $currentY,
|
||||
$barcodeSize, $barcodeSize
|
||||
);
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
} else {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE,
|
||||
'freesans', 'b', self::TAG_SIZE, 'R',
|
||||
$usableWidth, self::TAG_SIZE, true, 0
|
||||
);
|
||||
}
|
||||
|
||||
if ($record->has('title')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('title'),
|
||||
$currentX, $currentY,
|
||||
'freesans', 'b', self::TITLE_SIZE, 'L',
|
||||
$usableWidth, self::TITLE_SIZE, true, 0
|
||||
);
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
}
|
||||
|
||||
if ($record->has('barcode1d')) {
|
||||
static::write1DBarcode(
|
||||
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
|
||||
$currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Labels\Tapes\Dymo;
|
||||
|
||||
|
||||
class LabelWriter_2112283 extends LabelWriter
|
||||
{
|
||||
private const BARCODE_MARGIN = 1.80;
|
||||
private const TAG_SIZE = 2.80;
|
||||
private const TITLE_SIZE = 2.80;
|
||||
private const TITLE_MARGIN = 0.50;
|
||||
private const LABEL_SIZE = 2.80;
|
||||
private const LABEL_MARGIN = - 0.35;
|
||||
private const FIELD_SIZE = 2.80;
|
||||
private const FIELD_MARGIN = 0.15;
|
||||
|
||||
public function getUnit() { return 'mm'; }
|
||||
public function getWidth() { return 54; }
|
||||
public function getHeight() { return 25; }
|
||||
public function getSupportAssetTag() { return true; }
|
||||
public function getSupport1DBarcode() { return true; }
|
||||
public function getSupport2DBarcode() { return true; }
|
||||
public function getSupportFields() { return 5; }
|
||||
public function getSupportLogo() { return false; }
|
||||
public function getSupportTitle() { return true; }
|
||||
|
||||
public function preparePDF($pdf) {}
|
||||
|
||||
public function write($pdf, $record) {
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$usableWidth = $pa->w;
|
||||
|
||||
$barcodeSize = $pa->h - self::TAG_SIZE;
|
||||
|
||||
if ($record->has('barcode2d')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE,
|
||||
'freesans', 'b', self::TAG_SIZE, 'C',
|
||||
$barcodeSize, self::TAG_SIZE, true, 0
|
||||
);
|
||||
static::write2DBarcode(
|
||||
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
|
||||
$currentX, $currentY,
|
||||
$barcodeSize, $barcodeSize
|
||||
);
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
} else {
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$pa->x1, $pa->y2 - self::TAG_SIZE,
|
||||
'freesans', 'b', self::TAG_SIZE, 'R',
|
||||
$usableWidth, self::TAG_SIZE, true, 0
|
||||
);
|
||||
}
|
||||
|
||||
if ($record->has('title')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('title'),
|
||||
$currentX, $currentY,
|
||||
'freesans', 'b', self::TITLE_SIZE, 'L',
|
||||
$usableWidth, self::TITLE_SIZE, true, 0
|
||||
);
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
}
|
||||
|
||||
if ($record->has('barcode1d')) {
|
||||
static::write1DBarcode(
|
||||
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
|
||||
$currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,6 +53,7 @@ class License extends Depreciable
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'min_amt' => 'numeric|nullable|gte:0',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -81,6 +82,7 @@ class License extends Depreciable
|
||||
'supplier_id',
|
||||
'termination_date',
|
||||
'user_id',
|
||||
'min_amt',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
|
||||
@@ -95,7 +95,10 @@ class Location extends SnipeModel
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether or not this location can be deleted
|
||||
* Determine whether or not this location can be deleted.
|
||||
*
|
||||
* This method requires the eager loading of the relationships in order to determine whether
|
||||
* it can be deleted. It's tempting to load those here, but that increases the query load considerably.
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v3.0]
|
||||
@@ -103,10 +106,12 @@ class Location extends SnipeModel
|
||||
*/
|
||||
public function isDeletable()
|
||||
{
|
||||
|
||||
return Gate::allows('delete', $this)
|
||||
&& ($this->assignedAssets()->count() === 0)
|
||||
&& ($this->assets()->count() === 0)
|
||||
&& ($this->users()->count() === 0);
|
||||
&& ($this->assets_count === 0)
|
||||
&& ($this->assigned_assets_count === 0)
|
||||
&& ($this->children_count === 0)
|
||||
&& ($this->users_count === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -67,6 +67,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'gravatar',
|
||||
'vip',
|
||||
'autoassign_licenses',
|
||||
'website',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -120,6 +121,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'phone',
|
||||
'jobtitle',
|
||||
'employee_num',
|
||||
'website',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -335,7 +337,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
*/
|
||||
public function licenses()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\License::class, 'license_seats', 'assigned_to', 'license_id')->withPivot('id');
|
||||
return $this->belongsToMany(\App\Models\License::class, 'license_seats', 'assigned_to', 'license_id')->withPivot('id', 'created_at', 'updated_at');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,12 +43,12 @@ class CheckinAccessoryNotification extends Notification
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@ class CheckinAssetNotification extends Notification
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ class CheckinLicenseSeatNotification extends Notification
|
||||
{
|
||||
$notifyBy = [];
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -42,12 +42,12 @@ class CheckoutAccessoryNotification extends Notification
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ class CheckoutAssetNotification extends Notification
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@ class CheckoutConsumableNotification extends Notification
|
||||
public function via()
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = GoogleChatChannel::class;
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
|
||||
|
||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ class AccessoryPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.name'),
|
||||
'formatter' => 'accessoriesLinkFormatter',
|
||||
], [
|
||||
|
||||
@@ -38,10 +38,14 @@ class ActionlogPresenter extends Presenter
|
||||
|
||||
public function icon()
|
||||
{
|
||||
|
||||
|
||||
// User related icons
|
||||
if ($this->itemType() == 'user') {
|
||||
|
||||
if ($this->actionType()=='2fa reset') {
|
||||
return 'fa-solid fa-mobile-screen';
|
||||
}
|
||||
|
||||
if ($this->actionType()=='create new') {
|
||||
return 'fa-solid fa-user-plus';
|
||||
}
|
||||
@@ -61,6 +65,7 @@ class ActionlogPresenter extends Presenter
|
||||
if ($this->actionType()=='update') {
|
||||
return 'fa-solid fa-user-pen';
|
||||
}
|
||||
|
||||
return 'fa-solid fa-user';
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ class AssetMaintenancesPresenter extends Presenter
|
||||
'field' => 'title',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/asset_maintenances/form.title'),
|
||||
], [
|
||||
'field' => 'start_date',
|
||||
|
||||
@@ -35,6 +35,7 @@ class AssetModelPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'visible' => true,
|
||||
'title' => trans('general.name'),
|
||||
'formatter' => 'modelsLinkFormatter',
|
||||
|
||||
@@ -55,6 +55,7 @@ class AssetPresenter extends Presenter
|
||||
'field' => 'asset_tag',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/hardware/table.asset_tag'),
|
||||
'visible' => true,
|
||||
'formatter' => 'hardwareLinkFormatter',
|
||||
@@ -195,6 +196,14 @@ class AssetPresenter extends Presenter
|
||||
'visible' => false,
|
||||
'title' => trans('admin/hardware/form.warranty_expires'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'requestable',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('admin/hardware/general.requestable'),
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
|
||||
], [
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
@@ -244,6 +253,13 @@ class AssetPresenter extends Presenter
|
||||
'visible' => false,
|
||||
'title' => trans('admin/hardware/table.checkout_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'last_checkin',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('admin/hardware/table.last_checkin_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'expected_checkin',
|
||||
'searchable' => false,
|
||||
@@ -308,7 +324,7 @@ class AssetPresenter extends Presenter
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||
'visible' => true,
|
||||
'formatter' => 'hardwareInOutFormatter',
|
||||
|
||||
@@ -25,6 +25,7 @@ class CategoryPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'categoriesLinkFormatter',
|
||||
|
||||
@@ -25,7 +25,7 @@ class CompanyPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/companies/table.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'companiesLinkFormatter',
|
||||
|
||||
@@ -126,7 +126,7 @@ class ComponentPresenter extends Presenter
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||
'visible' => true,
|
||||
'formatter' => 'componentsInOutFormatter',
|
||||
|
||||
@@ -35,6 +35,7 @@ class ConsumablePresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'consumablesLinkFormatter',
|
||||
|
||||
@@ -25,6 +25,7 @@ class DepreciationPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'depreciationsLinkFormatter',
|
||||
|
||||
@@ -34,6 +34,7 @@ class DepreciationReportPresenter extends Presenter
|
||||
"field" => "name",
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
'switchable' => false,
|
||||
"title" => trans('admin/hardware/form.name'),
|
||||
"visible" => false,
|
||||
], [
|
||||
|
||||
@@ -33,6 +33,7 @@ class LicensePresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.name'),
|
||||
'formatter' => 'licensesLinkFormatter',
|
||||
], [
|
||||
@@ -89,7 +90,14 @@ class LicensePresenter extends Presenter
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/accessories/general.remaining'),
|
||||
], [
|
||||
],
|
||||
[
|
||||
'field' => 'min_amt',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'title' => trans('mail.min_QTY'),
|
||||
'formatter' => 'minAmtFormatter',
|
||||
],[
|
||||
'field' => 'purchase_date',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
@@ -179,7 +187,7 @@ class LicensePresenter extends Presenter
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||
'visible' => true,
|
||||
'formatter' => 'licensesInOutFormatter',
|
||||
@@ -273,7 +281,7 @@ class LicensePresenter extends Presenter
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||
'visible' => true,
|
||||
'formatter' => 'licenseSeatInOutFormatter',
|
||||
|
||||
@@ -14,7 +14,11 @@ class LocationPresenter extends Presenter
|
||||
public static function dataTableLayout()
|
||||
{
|
||||
$layout = [
|
||||
|
||||
[
|
||||
'field' => 'bulk_selectable',
|
||||
'checkbox' => true,
|
||||
'formatter' => 'checkboxEnabledFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'id',
|
||||
'searchable' => false,
|
||||
@@ -27,6 +31,7 @@ class LocationPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/locations/table.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'locationsLinkFormatter',
|
||||
|
||||
@@ -27,6 +27,7 @@ class ManufacturerPresenter extends Presenter
|
||||
'field' => 'name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/manufacturers/table.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'manufacturersLinkFormatter',
|
||||
|
||||
@@ -38,7 +38,7 @@ class UserPresenter extends Presenter
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => 'Avatar',
|
||||
'title' => trans('general.importer.avatar'),
|
||||
'visible' => false,
|
||||
'formatter' => 'imageFormatter',
|
||||
],
|
||||
@@ -122,6 +122,15 @@ class UserPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'phoneFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'website',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.website'),
|
||||
'visible' => false,
|
||||
'formatter' => 'externalLinkFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'address',
|
||||
'searchable' => true,
|
||||
@@ -166,7 +175,7 @@ class UserPresenter extends Presenter
|
||||
'field' => 'username',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/users/table.username'),
|
||||
'visible' => true,
|
||||
'formatter' => 'usersLinkFormatter',
|
||||
|
||||
@@ -39,24 +39,12 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
$limit = abs($int_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('------------------------------');
|
||||
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use DB;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Validator;
|
||||
@@ -294,6 +297,39 @@ class ValidationServiceProvider extends ServiceProvider
|
||||
Validator::extend('not_array', function ($attribute, $value, $parameters, $validator) {
|
||||
return !is_array($value);
|
||||
});
|
||||
|
||||
// This is only used in Models/CustomFieldset.php - it does automatic validation for checkboxes by making sure
|
||||
// that the submitted values actually exist in the options.
|
||||
Validator::extend('checkboxes', function ($attribute, $value, $parameters, $validator){
|
||||
$field = CustomField::where('db_column', $attribute)->first();
|
||||
$options = $field->formatFieldValuesAsArray();
|
||||
|
||||
if(is_array($value)) {
|
||||
$invalid = array_diff($value, $options);
|
||||
if(count($invalid) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// for legacy, allows users to submit a comma separated string of options
|
||||
elseif(!is_array($value)) {
|
||||
$exploded = array_map('trim', explode(',', $value));
|
||||
$invalid = array_diff($exploded, $options);
|
||||
if(count($invalid) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Validates that a radio button option exists
|
||||
Validator::extend('radio_buttons', function ($attribute, $value) {
|
||||
$field = CustomField::where('db_column', $attribute)->first();
|
||||
$options = $field->formatFieldValuesAsArray();
|
||||
|
||||
return in_array($value, $options);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+17
-29
@@ -38,10 +38,10 @@ class Label implements View
|
||||
$settings = $this->data->get('settings');
|
||||
$assets = $this->data->get('assets');
|
||||
$offset = $this->data->get('offset');
|
||||
$template = $this->data->get('template');
|
||||
$template = LabelModel::find($settings->label2_template);
|
||||
|
||||
// If disabled, pass to legacy view
|
||||
if ((!$settings->label2_enable) && (!$template)) {
|
||||
if ((!$settings->label2_enable)) {
|
||||
return view('hardware/labels')
|
||||
->with('assets', $assets)
|
||||
->with('settings', $settings)
|
||||
@@ -49,13 +49,6 @@ class Label implements View
|
||||
->with('count', $this->data->get('count'));
|
||||
}
|
||||
|
||||
// If a specific template was set, use it, otherwise fall back to default
|
||||
if (empty($template)) {
|
||||
$template = LabelModel::find($settings->label2_template);
|
||||
} elseif (is_string($template)) {
|
||||
$template = LabelModel::find($template);
|
||||
}
|
||||
|
||||
$template->validate();
|
||||
|
||||
$pdf = new TCPDF(
|
||||
@@ -90,13 +83,9 @@ class Label implements View
|
||||
$assetData->put('id', $asset->id);
|
||||
$assetData->put('tag', $asset->asset_tag);
|
||||
|
||||
if ($template->getSupportTitle()) {
|
||||
|
||||
if ($asset->company && !empty($settings->label2_title)) {
|
||||
$title = str_replace('{COMPANY}', $asset->company->name, $settings->label2_title);
|
||||
$settings->qr_text;
|
||||
$assetData->put('title', $title);
|
||||
}
|
||||
if ($template->getSupportTitle() && !empty($settings->label2_title)) {
|
||||
$title = str_replace('{COMPANY}', data_get($asset, 'company.name'), $settings->label2_title);
|
||||
$assetData->put('title', $title);
|
||||
}
|
||||
|
||||
if ($template->getSupportLogo()) {
|
||||
@@ -116,16 +105,15 @@ class Label implements View
|
||||
}
|
||||
}
|
||||
|
||||
if ($template->getSupport1DBarcode()) {
|
||||
$barcode1DType = $settings->label2_1d_type;
|
||||
$barcode1DType = ($barcode1DType == 'default') ?
|
||||
(($settings->alt_barcode_enabled) ? $settings->alt_barcode : null) :
|
||||
$barcode1DType;
|
||||
if ($barcode1DType != 'none') {
|
||||
$assetData->put('barcode1d', (object)[
|
||||
'type' => $barcode1DType,
|
||||
'content' => $asset->asset_tag,
|
||||
]);
|
||||
if ($settings->alt_barcode_enabled) {
|
||||
if ($template->getSupport1DBarcode()) {
|
||||
$barcode1DType = $settings->alt_barcode;
|
||||
if ($barcode1DType != 'none') {
|
||||
$assetData->put('barcode1d', (object)[
|
||||
'type' => $barcode1DType,
|
||||
'content' => $asset->asset_tag,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +126,7 @@ class Label implements View
|
||||
switch ($settings->label2_2d_target) {
|
||||
case 'ht_tag': $barcode2DTarget = route('ht/assetTag', $asset->asset_tag); break;
|
||||
case 'hardware_id':
|
||||
default: $barcode2DTarget = route('hardware.show', $asset->id); break;
|
||||
default: $barcode2DTarget = route('hardware.show', ['hardware' => $asset->id]); break;
|
||||
}
|
||||
$assetData->put('barcode2d', (object)[
|
||||
'type' => $barcode2DType,
|
||||
@@ -158,7 +146,7 @@ class Label implements View
|
||||
|
||||
return $toAdd ? $myFields->push($toAdd) : $myFields;
|
||||
}, new Collection());
|
||||
|
||||
|
||||
$assetData->put('fields', $fields->take($template->getSupportFields()));
|
||||
|
||||
return $assetData;
|
||||
@@ -216,4 +204,4 @@ class Label implements View
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -58,7 +58,6 @@
|
||||
"league/flysystem-aws-s3-v3": "^1.0",
|
||||
"league/flysystem-cached-adapter": "^1.1",
|
||||
"livewire/livewire": "^2.4",
|
||||
"mediconesystems/livewire-datatables": "^0.5.0",
|
||||
"neitanod/forceutf8": "^2.0",
|
||||
"nesbot/carbon": "^2.32",
|
||||
"nunomaduro/collision": "^5.4",
|
||||
@@ -77,7 +76,8 @@
|
||||
"watson/validating": "^6.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ldap": "*"
|
||||
"ext-ldap": "*",
|
||||
"ext-zip": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^6.6",
|
||||
|
||||
Generated
+13
-553
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "9cca85cd0074df9154765b1ab52f83fa",
|
||||
"content-hash": "0536c48de3ba12fdeb01bac07fcd7172",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alek13/slack",
|
||||
@@ -2165,57 +2165,6 @@
|
||||
},
|
||||
"time": "2019-12-30T22:54:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
|
||||
"reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"library/HTMLPurifier.composer.php"
|
||||
],
|
||||
"psr-0": {
|
||||
"HTMLPurifier": "library/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/library/HTMLPurifier/Language/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Edward Z. Yang",
|
||||
"email": "admin@htmlpurifier.org",
|
||||
"homepage": "http://ezyang.com"
|
||||
}
|
||||
],
|
||||
"description": "Standards compliant HTML filter written in PHP",
|
||||
"homepage": "http://htmlpurifier.org/",
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ezyang/htmlpurifier/issues",
|
||||
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.14.0"
|
||||
},
|
||||
"time": "2021-12-25T01:21:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "facade/flare-client-php",
|
||||
"version": "1.9.1",
|
||||
@@ -5133,268 +5082,6 @@
|
||||
],
|
||||
"time": "2022-06-19T02:54:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maatwebsite/excel",
|
||||
"version": "3.1.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SpartnerNL/Laravel-Excel.git",
|
||||
"reference": "8a54972e3d616c74687c3cbff15765555761885c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/8a54972e3d616c74687c3cbff15765555761885c",
|
||||
"reference": "8a54972e3d616c74687c3cbff15765555761885c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"illuminate/support": "5.8.*|^6.0|^7.0|^8.0|^9.0",
|
||||
"php": "^7.0|^8.0",
|
||||
"phpoffice/phpspreadsheet": "^1.18"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.0|^7.0",
|
||||
"predis/predis": "^1.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Maatwebsite\\Excel\\ExcelServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Excel": "Maatwebsite\\Excel\\Facades\\Excel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Maatwebsite\\Excel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Patrick Brouwers",
|
||||
"email": "patrick@spartner.nl"
|
||||
}
|
||||
],
|
||||
"description": "Supercharged Excel exports and imports in Laravel",
|
||||
"keywords": [
|
||||
"PHPExcel",
|
||||
"batch",
|
||||
"csv",
|
||||
"excel",
|
||||
"export",
|
||||
"import",
|
||||
"laravel",
|
||||
"php",
|
||||
"phpspreadsheet"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/SpartnerNL/Laravel-Excel/issues",
|
||||
"source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.40"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://laravel-excel.com/commercial-support",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/patrickbrouwers",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-02T13:50:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maennchen/zipstream-php",
|
||||
"version": "2.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
||||
"reference": "211e9ba1530ea5260b45d90c9ea252f56ec52729"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/211e9ba1530ea5260b45d90c9ea252f56ec52729",
|
||||
"reference": "211e9ba1530ea5260b45d90c9ea252f56ec52729",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"myclabs/php-enum": "^1.5",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"symfony/polyfill-mbstring": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-zip": "*",
|
||||
"guzzlehttp/guzzle": "^6.5.3 || ^7.2.0",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"php-coveralls/php-coveralls": "^2.4",
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.4.2",
|
||||
"vimeo/psalm": "^4.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ZipStream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paul Duncan",
|
||||
"email": "pabs@pablotron.org"
|
||||
},
|
||||
{
|
||||
"name": "Jonatan Männchen",
|
||||
"email": "jonatan@maennchen.ch"
|
||||
},
|
||||
{
|
||||
"name": "Jesse Donat",
|
||||
"email": "donatj@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "András Kolesár",
|
||||
"email": "kolesar@kolesar.hu"
|
||||
}
|
||||
],
|
||||
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
||||
"keywords": [
|
||||
"stream",
|
||||
"zip"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
||||
"source": "https://github.com/maennchen/ZipStream-PHP/tree/2.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/maennchen",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/zipstream",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-18T15:52:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/complex",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||
"reference": "ab8bc271e404909db09ff2d5ffa1e538085c0f22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/ab8bc271e404909db09ff2d5ffa1e538085c0f22",
|
||||
"reference": "ab8bc271e404909db09ff2d5ffa1e538085c0f22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
|
||||
"squizlabs/php_codesniffer": "^3.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Complex\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with complex numbers",
|
||||
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||
"keywords": [
|
||||
"complex",
|
||||
"mathematics"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.1"
|
||||
},
|
||||
"time": "2021-06-29T15:32:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/matrix",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||
"reference": "c66aefcafb4f6c269510e9ac46b82619a904c576"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/c66aefcafb4f6c269510e9ac46b82619a904c576",
|
||||
"reference": "c66aefcafb4f6c269510e9ac46b82619a904c576",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"phpdocumentor/phpdocumentor": "2.*",
|
||||
"phploc/phploc": "^4.0",
|
||||
"phpmd/phpmd": "2.*",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
|
||||
"sebastian/phpcpd": "^4.0",
|
||||
"squizlabs/php_codesniffer": "^3.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Matrix\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@demon-angel.eu"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with matrices",
|
||||
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||
"keywords": [
|
||||
"mathematics",
|
||||
"matrix",
|
||||
"vector"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.0"
|
||||
},
|
||||
"time": "2021-07-01T19:01:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.8.1",
|
||||
@@ -5528,69 +5215,6 @@
|
||||
},
|
||||
"time": "2021-12-27T18:49:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mediconesystems/livewire-datatables",
|
||||
"version": "v0.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MedicOneSystems/livewire-datatables.git",
|
||||
"reference": "bf6f24d529208e6bdec58276e92792719c73c827"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MedicOneSystems/livewire-datatables/zipball/bf6f24d529208e6bdec58276e92792719c73c827",
|
||||
"reference": "bf6f24d529208e6bdec58276e92792719c73c827",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^7.0|^8.0",
|
||||
"livewire/livewire": "^1.2|^2.0",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"php": "^7.2.5|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/legacy-factories": "^1.0.4",
|
||||
"orchestra/testbench": "^4.0|5.0|6.0",
|
||||
"phpunit/phpunit": "^8.0|9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Mediconesystems\\LivewireDatatables\\LivewireDatatablesServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"LivewireDatatables": "Mediconesystems\\LivewireDatatables\\LivewireDatatablesFacade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mediconesystems\\LivewireDatatables\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Salmon",
|
||||
"email": "mark.salmon@mediconesystems.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"homepage": "https://github.com/mediconesystems/livewire-datatables",
|
||||
"keywords": [
|
||||
"livewire-datatables",
|
||||
"mediconesystems"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MedicOneSystems/livewire-datatables/issues",
|
||||
"source": "https://github.com/MedicOneSystems/livewire-datatables/tree/v0.5.4"
|
||||
},
|
||||
"time": "2021-08-09T20:37:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.7.0",
|
||||
@@ -5761,66 +5385,6 @@
|
||||
},
|
||||
"time": "2023-08-25T10:54:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/php-enum",
|
||||
"version": "1.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/php-enum.git",
|
||||
"reference": "b942d263c641ddb5190929ff840c68f78713e937"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937",
|
||||
"reference": "b942d263c641ddb5190929ff840c68f78713e937",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^7.3 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "1.*",
|
||||
"vimeo/psalm": "^4.6.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"MyCLabs\\Enum\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP Enum contributors",
|
||||
"homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP Enum implementation",
|
||||
"homepage": "http://github.com/myclabs/php-enum",
|
||||
"keywords": [
|
||||
"enum"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/php-enum/issues",
|
||||
"source": "https://github.com/myclabs/php-enum/tree/1.8.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/mnapoli",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-05T08:18:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "neitanod/forceutf8",
|
||||
"version": "v2.0.4",
|
||||
@@ -6701,16 +6265,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phenx/php-svg-lib",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||
"reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456"
|
||||
"reference": "732faa9fb4309221e2bd9b2fda5de44f947133aa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8a8a1ebcf6aea861ef30197999f096f7bd4b4456",
|
||||
"reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456",
|
||||
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/732faa9fb4309221e2bd9b2fda5de44f947133aa",
|
||||
"reference": "732faa9fb4309221e2bd9b2fda5de44f947133aa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6741,9 +6305,9 @@
|
||||
"homepage": "https://github.com/PhenX/php-svg-lib",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||
"source": "https://github.com/dompdf/php-svg-lib/tree/0.5.1"
|
||||
"source": "https://github.com/dompdf/php-svg-lib/tree/0.5.2"
|
||||
},
|
||||
"time": "2023-12-11T20:56:08+00:00"
|
||||
"time": "2024-02-07T12:49:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/message-factory",
|
||||
@@ -6960,110 +6524,6 @@
|
||||
},
|
||||
"time": "2022-03-15T21:29:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoffice/phpspreadsheet",
|
||||
"version": "1.24.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||
"reference": "69991111e05fca3ff7398e1e7fca9ebed33efec6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/69991111e05fca3ff7398e1e7fca9ebed33efec6",
|
||||
"reference": "69991111e05fca3ff7398e1e7fca9ebed33efec6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": "*",
|
||||
"ezyang/htmlpurifier": "^4.13",
|
||||
"maennchen/zipstream-php": "^2.1",
|
||||
"markbaker/complex": "^3.0",
|
||||
"markbaker/matrix": "^3.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/simple-cache": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||
"dompdf/dompdf": "^1.0 || ^2.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.2",
|
||||
"jpgraph/jpgraph": "^4.0",
|
||||
"mpdf/mpdf": "8.1.1",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpstan/phpstan": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^8.5 || ^9.0",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"tecnickcom/tcpdf": "^6.4"
|
||||
},
|
||||
"suggest": {
|
||||
"dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)",
|
||||
"jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maarten Balliauw",
|
||||
"homepage": "https://blog.maartenballiauw.be"
|
||||
},
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"homepage": "https://markbakeruk.net"
|
||||
},
|
||||
{
|
||||
"name": "Franck Lefevre",
|
||||
"homepage": "https://rootslabs.net"
|
||||
},
|
||||
{
|
||||
"name": "Erik Tilt"
|
||||
},
|
||||
{
|
||||
"name": "Adrien Crivelli"
|
||||
}
|
||||
],
|
||||
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||
"keywords": [
|
||||
"OpenXML",
|
||||
"excel",
|
||||
"gnumeric",
|
||||
"ods",
|
||||
"php",
|
||||
"spreadsheet",
|
||||
"xls",
|
||||
"xlsx"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.24.1"
|
||||
},
|
||||
"time": "2022-07-18T19:50:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.8.1",
|
||||
@@ -7137,16 +6597,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.34",
|
||||
"version": "3.0.37",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "56c79f16a6ae17e42089c06a2144467acc35348a"
|
||||
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a",
|
||||
"reference": "56c79f16a6ae17e42089c06a2144467acc35348a",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
|
||||
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7227,7 +6687,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.34"
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.37"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7243,7 +6703,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-27T11:13:31+00:00"
|
||||
"time": "2024-03-03T02:14:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'enable_csp' => env('ENABLE_CSP', false),
|
||||
'enable_csp' => env('ENABLE_CSP', true),
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -174,4 +174,17 @@ return [
|
||||
|
||||
'bs_table_storage' => env('BS_TABLE_STORAGE', 'cookieStorage'),
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bootstrap Table Enable Deeplinking
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Use deeplinks to directly link to search results, sorting, and pagination
|
||||
|
|
||||
| More info: https://github.com/generals-space/bootstrap-table-addrbar/blob/master/readme(EN).md
|
||||
*/
|
||||
|
||||
'bs_table_addrbar' => env('BS_TABLE_DEEPLINK', true),
|
||||
|
||||
];
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v6.3.1',
|
||||
'full_app_version' => 'v6.3.1 - build 12672-g00cea3eb3',
|
||||
'build_version' => '12672',
|
||||
'app_version' => 'v6.3.4',
|
||||
'full_app_version' => 'v6.3.4 - build 13139-g6f9ba6ede',
|
||||
'build_version' => '13139',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'g00cea3eb3',
|
||||
'full_hash' => 'v6.3.1-180-g00cea3eb3',
|
||||
'hash_version' => 'g6f9ba6ede',
|
||||
'full_hash' => 'v6.3.4-234-g6f9ba6ede',
|
||||
'branch' => 'master',
|
||||
);
|
||||
@@ -8,7 +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;
|
||||
|
||||
@@ -289,12 +288,13 @@ class AssetFactory extends Factory
|
||||
});
|
||||
}
|
||||
|
||||
public function assignedToUser()
|
||||
public function assignedToUser(User $user = null)
|
||||
{
|
||||
return $this->state(function () {
|
||||
return $this->state(function () use ($user) {
|
||||
return [
|
||||
'assigned_to' => User::factory(),
|
||||
'assigned_to' => $user->id ?? User::factory(),
|
||||
'assigned_type' => User::class,
|
||||
'last_checkout' => now()->subDay(),
|
||||
];
|
||||
});
|
||||
}
|
||||
@@ -352,4 +352,19 @@ class AssetFactory extends Factory
|
||||
{
|
||||
return $this->state(['requestable' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This allows bypassing model level validation if you want to purposefully
|
||||
* create an asset in an invalid state. Validation is turned back on
|
||||
* after the model is created via the factory.
|
||||
* @return AssetFactory
|
||||
*/
|
||||
public function canBeInvalidUponCreation()
|
||||
{
|
||||
return $this->afterMaking(function (Asset $asset) {
|
||||
$asset->setValidating(false);
|
||||
})->afterCreating(function (Asset $asset) {
|
||||
$asset->setValidating(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class DepartmentFactory extends Factory
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->word() . ' Department',
|
||||
'name' => $this->faker->unique()->word() . ' Department',
|
||||
'user_id' => User::factory()->superuser(),
|
||||
'location_id' => Location::factory(),
|
||||
];
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class LicenseSeatFactory extends Factory
|
||||
@@ -13,4 +14,13 @@ class LicenseSeatFactory extends Factory
|
||||
'license_id' => License::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
public function assignedToUser(User $user = null)
|
||||
{
|
||||
return $this->state(function () use ($user) {
|
||||
return [
|
||||
'assigned_to' => $user->id ?? User::factory(),
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddCreatedByToPermissionGroups extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('permission_groups', function (Blueprint $table) {
|
||||
$table->integer('created_by')->nullable()->default(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('permission_groups', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('permission_groups', 'created_by')) {
|
||||
$table->dropColumn('created_by');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddMinQtyToLicenses extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('licenses', function (Blueprint $table) {
|
||||
$table->integer('min_amt')->nullable()->default(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('licenses', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('licenses', 'min_amt')) {
|
||||
$table->dropColumn('min_amt');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UpdateLegacyLocale extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
//
|
||||
$table->string('locale', 10)->nullable()->default('en-US')->change();
|
||||
});
|
||||
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
//
|
||||
$table->string('locale', 10)->nullable()->default('en-US')->change();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
//
|
||||
$table->string('locale', 10)->nullable()->default(config('app.locale'))->change();
|
||||
});
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
//
|
||||
$table->string('locale', 10)->nullable()->default(config('app.locale'))->change();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,16 +17,23 @@ else
|
||||
fi
|
||||
|
||||
# create data directories
|
||||
# Note: Keep in sync with expected directories by the app
|
||||
# https://github.com/snipe/snipe-it/blob/master/app/Console/Commands/RestoreFromBackup.php#L232
|
||||
for dir in \
|
||||
'data/private_uploads' \
|
||||
'data/private_uploads/assets' \
|
||||
'data/private_uploads/accessories' \
|
||||
'data/private_uploads/audits' \
|
||||
'data/private_uploads/components' \
|
||||
'data/private_uploads/consumables' \
|
||||
'data/private_uploads/eula-pdfs' \
|
||||
'data/private_uploads/imports' \
|
||||
'data/private_uploads/assetmodels' \
|
||||
'data/private_uploads/users' \
|
||||
'data/private_uploads/licenses' \
|
||||
'data/private_uploads/signatures' \
|
||||
'data/uploads/accessories' \
|
||||
'data/uploads/assets' \
|
||||
'data/uploads/avatars' \
|
||||
'data/uploads/barcodes' \
|
||||
'data/uploads/categories' \
|
||||
|
||||
Generated
+62
-33
@@ -1351,7 +1351,8 @@
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz",
|
||||
"integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ=="
|
||||
"integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/source-map": {
|
||||
"version": "0.3.5",
|
||||
@@ -1363,14 +1364,42 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="
|
||||
},
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1565,9 +1594,9 @@
|
||||
}
|
||||
},
|
||||
"@types/eslint": {
|
||||
"version": "8.56.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||
"integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==",
|
||||
"version": "8.56.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz",
|
||||
"integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==",
|
||||
"requires": {
|
||||
"@types/estree": "*",
|
||||
"@types/json-schema": "*"
|
||||
@@ -3348,9 +3377,9 @@
|
||||
"integrity": "sha1-EQPWvADPv6jPyaJZmrUYxVZD2j8="
|
||||
},
|
||||
"bootstrap-table": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.2.tgz",
|
||||
"integrity": "sha512-ZjZGcEXm/N7N/wAykmANWKKV+U+7AxgoNuBwWLrKbvAGT8XXS2f0OCiFmuMwpkqg7pDbF+ff9bEf/lOAlxcF1w=="
|
||||
"version": "1.22.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.3.tgz",
|
||||
"integrity": "sha512-YWQTXzmZBX6P4y6YW2mHOxqIAYyLKld2WecHuKSyYamimUE4KZ9YUsmAroSoS2Us1bPYXFaM+JCeTt6X0iKW+g=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
@@ -4983,9 +5012,9 @@
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
|
||||
"integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
|
||||
"version": "5.15.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz",
|
||||
"integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -16345,9 +16374,9 @@
|
||||
}
|
||||
},
|
||||
"jspdf-autotable": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.1.tgz",
|
||||
"integrity": "sha512-UjJqo80Z3/WUzDi4JipTGp0pAvNvR3Gsm38inJ5ZnwsJH0Lw4pEbssRSH6zMWAhR1ZkTrsDpQo5p6rZk987/AQ=="
|
||||
"version": "3.8.2",
|
||||
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.2.tgz",
|
||||
"integrity": "sha512-zW1ix99/mtR4MbIni7IqvrpfHmuTaICl6iv6wqjRN86Nxtwaw/QtOeDbpXqYSzHIJK9JvgtLM283sc5x+ipkJg=="
|
||||
},
|
||||
"junk": {
|
||||
"version": "3.1.0",
|
||||
@@ -20101,9 +20130,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.90.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz",
|
||||
"integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==",
|
||||
"version": "5.90.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz",
|
||||
"integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==",
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.5",
|
||||
@@ -20142,9 +20171,9 @@
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.22",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
|
||||
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
@@ -20167,9 +20196,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001587",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz",
|
||||
"integrity": "sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA=="
|
||||
"version": "1.0.30001596",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz",
|
||||
"integrity": "sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ=="
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
@@ -20177,9 +20206,9 @@
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.670",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.670.tgz",
|
||||
"integrity": "sha512-hcijYOWjOtjKrKPtNA6tuLlA/bTLO3heFG8pQA6mLpq7dRydSWicXova5lyxDzp1iVJaYhK7J2OQlGE52KYn7A=="
|
||||
"version": "1.4.698",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.698.tgz",
|
||||
"integrity": "sha512-f9iZD1t3CLy1AS6vzM5EKGa6p9pRcOeEFXRFbaG2Ta+Oe7MkfRQ3fsvPYidzHe1h4i0JvIvpcY55C+B6BZNGtQ=="
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
@@ -20210,9 +20239,9 @@
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.27.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
|
||||
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
|
||||
"version": "5.29.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz",
|
||||
"integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==",
|
||||
"requires": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
|
||||
+4
-4
@@ -33,13 +33,13 @@
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"admin-lte": "^2.4.18",
|
||||
"ajv": "^6.12.6",
|
||||
"alpinejs": "^3.13.5",
|
||||
"alpinejs": "3.13.5",
|
||||
"blueimp-file-upload": "^9.34.0",
|
||||
"bootstrap": "^3.4.1",
|
||||
"bootstrap-colorpicker": "^2.5.3",
|
||||
"bootstrap-datepicker": "^1.10.0",
|
||||
"bootstrap-less": "^3.3.8",
|
||||
"bootstrap-table": "1.22.2",
|
||||
"bootstrap-table": "1.22.3",
|
||||
"chart.js": "^2.9.4",
|
||||
"clipboard": "^2.0.11",
|
||||
"css-loader": "^5.0.0",
|
||||
@@ -49,7 +49,7 @@
|
||||
"jquery-slimscroll": "^1.3.8",
|
||||
"jquery-ui": "^1.13.2",
|
||||
"jquery.iframe-transport": "^1.0.0",
|
||||
"jspdf-autotable": "^3.8.0",
|
||||
"jspdf-autotable": "^3.8.2",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^5.0",
|
||||
"list.js": "^1.5.0",
|
||||
@@ -59,6 +59,6 @@
|
||||
"tableexport.jquery.plugin": "1.28.0",
|
||||
"tether": "^1.4.0",
|
||||
"vue-resource": "^1.5.2",
|
||||
"webpack": "^5.90.0"
|
||||
"webpack": "^5.90.2"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"/js/build/app.js": "/js/build/app.js?id=cad71122a8a3f0cd6c5960e95f4f0f8a",
|
||||
"/js/build/app.js": "/js/build/app.js?id=6bbc4dd6b643fefe492261fdfe6fae5a",
|
||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=6a7f37afafaaf9ccea99a7391cdf02b2",
|
||||
"/css/build/app.css": "/css/build/app.css?id=ea3875faceb1d09c162d00fbf5b4df57",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=87c4587df4ab5c64e0e3ee920310ba2a",
|
||||
"/css/build/app.css": "/css/build/app.css?id=28a7726dc9fa61365d36ed7067461490",
|
||||
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=f25c77ed07053646a42e9c19923d24fa",
|
||||
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=268041e902b019730c23ee3875838005",
|
||||
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=d409d9b1a3b69247df8b98941ba06e33",
|
||||
@@ -18,7 +18,7 @@
|
||||
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
||||
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460",
|
||||
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=2ef1965d45a0a72336dd8e9b93f82d80",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=3a58b0695460d60eaed66bc3b7f4e796",
|
||||
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=69e5d8e4e818f05fd882cceb758d1eba",
|
||||
@@ -29,10 +29,10 @@
|
||||
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=a0feb384c3c6071947a49708f2b0bc85",
|
||||
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=e24ec0b8661f7fa333b29444df39e399",
|
||||
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=e11465c0eff0549edd4e8ea6bbcf242f",
|
||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=afa255bf30b2a7c11a97e3165128d183",
|
||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=99c395f0bab5966f32f63f4e55899e64",
|
||||
"/js/build/vendor.js": "/js/build/vendor.js?id=a2b971da417306a63385c8098acfe4af",
|
||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=29340c70d13855fa0165cd4d799c6f5b",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=a9bde3f908f73634c0d1b4cd3f835092",
|
||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=857da5daffd13e0553510e5ccd410c79",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=fca6ea9956fd827d9790c08e0e982b22",
|
||||
"/js/dist/all-defer.js": "/js/dist/all-defer.js?id=19ccc62a8f1ea103dede4808837384d4",
|
||||
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
||||
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0ed42b67f9b02a74815e885bfd9e3f66",
|
||||
|
||||
@@ -887,4 +887,7 @@ input[type="radio"]:checked::before {
|
||||
|
||||
.separator:not(:empty)::after {
|
||||
margin-left: .25em;
|
||||
}
|
||||
.datepicker.dropdown-menu {
|
||||
z-index: 1030 !important;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'personal_api_keys' => 'crwdns6798:0crwdne6798:0',
|
||||
'api_key_warning' => 'crwdns6800:0crwdne6800:0',
|
||||
'api_base_url' => 'crwdns6802:0crwdne6802:0',
|
||||
'api_base_url_endpoint' => 'crwdns6804:0crwdne6804:0',
|
||||
'api_token_expiration_time' => 'crwdns6806:0crwdne6806:0',
|
||||
'api_reference' => 'crwdns6808:0crwdne6808:0',
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'accessory_category' => 'crwdns1207:0crwdne1207:0',
|
||||
'accessory_name' => 'crwdns1208:0crwdne1208:0',
|
||||
'checkout' => 'crwdns1604:0crwdne1604:0',
|
||||
'checkin' => 'crwdns1605:0crwdne1605:0',
|
||||
'create' => 'crwdns1385:0crwdne1385:0',
|
||||
'edit' => 'crwdns1606:0crwdne1606:0',
|
||||
'eula_text' => 'crwdns1210:0crwdne1210:0',
|
||||
'eula_text_help' => 'crwdns1211:0crwdne1211:0',
|
||||
'require_acceptance' => 'crwdns1212:0crwdne1212:0',
|
||||
'no_default_eula' => 'crwdns1213:0crwdne1213:0',
|
||||
'total' => 'crwdns1215:0crwdne1215:0',
|
||||
'remaining' => 'crwdns1216:0crwdne1216:0',
|
||||
'update' => 'crwdns1386:0crwdne1386:0',
|
||||
'use_default_eula' => 'crwdns1218:0crwdne1218:0',
|
||||
'use_default_eula_disabled' => 'crwdns1219:0crwdne1219:0',
|
||||
'clone' => 'crwdns11443:0crwdne11443:0',
|
||||
'delete_disabled' => 'crwdns11597:0crwdne11597:0',
|
||||
|
||||
);
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
'does_not_exist' => 'crwdns5810:0crwdne5810:0',
|
||||
'not_found' => 'crwdns11848:0crwdne11848:0',
|
||||
'assoc_users' => 'crwdns1221:0crwdne1221:0',
|
||||
|
||||
'create' => array(
|
||||
'error' => 'crwdns1468:0crwdne1468:0',
|
||||
'success' => 'crwdns1469:0crwdne1469:0'
|
||||
),
|
||||
|
||||
'update' => array(
|
||||
'error' => 'crwdns1470:0crwdne1470:0',
|
||||
'success' => 'crwdns1471:0crwdne1471:0'
|
||||
),
|
||||
|
||||
'delete' => array(
|
||||
'confirm' => 'crwdns1607:0crwdne1607:0',
|
||||
'error' => 'crwdns1608:0crwdne1608:0',
|
||||
'success' => 'crwdns1609:0crwdne1609:0'
|
||||
),
|
||||
|
||||
'checkout' => array(
|
||||
'error' => 'crwdns1229:0crwdne1229:0',
|
||||
'success' => 'crwdns1230:0crwdne1230:0',
|
||||
'unavailable' => 'crwdns11523:0crwdne11523:0',
|
||||
'user_does_not_exist' => 'crwdns1231:0crwdne1231:0'
|
||||
),
|
||||
|
||||
'checkin' => array(
|
||||
'error' => 'crwdns1232:0crwdne1232:0',
|
||||
'success' => 'crwdns1233:0crwdne1233:0',
|
||||
'user_does_not_exist' => 'crwdns1234:0crwdne1234:0'
|
||||
)
|
||||
|
||||
|
||||
);
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'dl_csv' => 'crwdns1421:0crwdne1421:0',
|
||||
'eula_text' => 'crwdns1235:0crwdne1235:0',
|
||||
'id' => 'crwdns1236:0crwdne1236:0',
|
||||
'require_acceptance' => 'crwdns1237:0crwdne1237:0',
|
||||
'title' => 'crwdns1238:0crwdne1238:0',
|
||||
|
||||
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'asset_maintenance_type' => 'crwdns11333:0crwdne11333:0',
|
||||
'title' => 'crwdns1354:0crwdne1354:0',
|
||||
'start_date' => 'crwdns11335:0crwdne11335:0',
|
||||
'completion_date' => 'crwdns11337:0crwdne11337:0',
|
||||
'cost' => 'crwdns1357:0crwdne1357:0',
|
||||
'is_warranty' => 'crwdns1358:0crwdne1358:0',
|
||||
'asset_maintenance_time' => 'crwdns11339:0crwdne11339:0',
|
||||
'notes' => 'crwdns1360:0crwdne1360:0',
|
||||
'update' => 'crwdns11341:0crwdne11341:0',
|
||||
'create' => 'crwdns11343:0crwdne11343:0'
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'asset_maintenances' => 'crwdns1363:0crwdne1363:0',
|
||||
'edit' => 'crwdns1364:0crwdne1364:0',
|
||||
'delete' => 'crwdns1365:0crwdne1365:0',
|
||||
'view' => 'crwdns1366:0crwdne1366:0',
|
||||
'repair' => 'crwdns1367:0crwdne1367:0',
|
||||
'maintenance' => 'crwdns1368:0crwdne1368:0',
|
||||
'upgrade' => 'crwdns1369:0crwdne1369:0',
|
||||
'calibration' => 'crwdns5812:0crwdne5812:0',
|
||||
'software_support' => 'crwdns5814:0crwdne5814:0',
|
||||
'hardware_support' => 'crwdns5816:0crwdne5816:0',
|
||||
'configuration_change' => 'crwdns10530:0crwdne10530:0',
|
||||
'pat_test' => 'crwdns10532:0crwdne10532:0',
|
||||
];
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'not_found' => 'crwdns1370:0crwdne1370:0',
|
||||
'delete' => [
|
||||
'confirm' => 'crwdns1371:0crwdne1371:0',
|
||||
'error' => 'crwdns1372:0crwdne1372:0',
|
||||
'success' => 'crwdns1373:0crwdne1373:0',
|
||||
],
|
||||
'create' => [
|
||||
'error' => 'crwdns1374:0crwdne1374:0',
|
||||
'success' => 'crwdns1375:0crwdne1375:0',
|
||||
],
|
||||
'edit' => [
|
||||
'error' => 'crwdns1903:0crwdne1903:0',
|
||||
'success' => 'crwdns1904:0crwdne1904:0',
|
||||
],
|
||||
'asset_maintenance_incomplete' => 'crwdns1376:0crwdne1376:0',
|
||||
'warranty' => 'crwdns1377:0crwdne1377:0',
|
||||
'not_warranty' => 'crwdns1378:0crwdne1378:0',
|
||||
];
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'title' => 'crwdns1379:0crwdne1379:0',
|
||||
'asset_name' => 'crwdns1794:0crwdne1794:0',
|
||||
'is_warranty' => 'crwdns1382:0crwdne1382:0',
|
||||
'dl_csv' => 'crwdns1383:0crwdne1383:0',
|
||||
];
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'asset_categories' => 'crwdns636:0crwdne636:0',
|
||||
'category_name' => 'crwdns637:0crwdne637:0',
|
||||
'checkin_email' => 'crwdns2034:0crwdne2034:0',
|
||||
'checkin_email_notification' => 'crwdns2035:0crwdne2035:0',
|
||||
'clone' => 'crwdns1239:0crwdne1239:0',
|
||||
'create' => 'crwdns638:0crwdne638:0',
|
||||
'edit' => 'crwdns1240:0crwdne1240:0',
|
||||
'email_will_be_sent_due_to_global_eula' => 'crwdns11697:0crwdne11697:0',
|
||||
'email_will_be_sent_due_to_category_eula' => 'crwdns11699:0crwdne11699:0',
|
||||
'eula_text' => 'crwdns1241:0crwdne1241:0',
|
||||
'eula_text_help' => 'crwdns1242:0crwdne1242:0',
|
||||
'name' => 'crwdns1835:0crwdne1835:0',
|
||||
'require_acceptance' => 'crwdns1243:0crwdne1243:0',
|
||||
'required_acceptance' => 'crwdns1244:0crwdne1244:0',
|
||||
'required_eula' => 'crwdns1245:0crwdne1245:0',
|
||||
'no_default_eula' => 'crwdns1246:0crwdne1246:0',
|
||||
'update' => 'crwdns639:0crwdne639:0',
|
||||
'use_default_eula' => 'crwdns1247:0crwdne1247:0',
|
||||
'use_default_eula_disabled' => 'crwdns1248:0crwdne1248:0',
|
||||
'use_default_eula_column' => 'crwdns6083:0crwdne6083:0',
|
||||
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user